From 260f082bae6dcf70aeae2cc3e24aecb55bdb1c99 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 25 Apr 2019 14:26:52 +0100 Subject: [PATCH] afs: Get an AFS3 ACL as an xattr Implement an xattr on AFS files called "afs.acl" that retrieves a file's ACL. It returns the raw AFS3 ACL from the result of calling FS.FetchACL, leaving any interpretation to userspace. Note that whilst YFS servers will respond to FS.FetchACL, this will render a more-advanced YFS ACL down. Use "afs.yfs.acl" instead for that. Signed-off-by: David Howells --- fs/afs/afs_fs.h | 1 + fs/afs/fsclient.c | 122 +++++++++++++++++++++++++++++++++++++ fs/afs/internal.h | 7 +++ fs/afs/xattr.c | 53 ++++++++++++++++ include/trace/events/afs.h | 1 + 5 files changed, 184 insertions(+) diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index ddfa88a7a9c0..4df1f1eec0ab 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h @@ -17,6 +17,7 @@ enum AFS_FS_Operations { FSFETCHDATA = 130, /* AFS Fetch file data */ + FSFETCHACL = 131, /* AFS Fetch file ACL */ FSFETCHSTATUS = 132, /* AFS Fetch file status */ FSSTOREDATA = 133, /* AFS Store file data */ FSSTORESTATUS = 135, /* AFS Store file status */ diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 9b73a57aa5cb..283f486c59f4 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -2391,3 +2391,125 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, afs_make_call(&fc->ac, call, GFP_NOFS); return afs_wait_for_call_to_complete(call, &fc->ac); } + +/* + * deliver reply data to an FS.FetchACL + */ +static int afs_deliver_fs_fetch_acl(struct afs_call *call) +{ + struct afs_vnode *vnode = call->reply[1]; + struct afs_acl *acl; + const __be32 *bp; + unsigned int size; + int ret; + + _enter("{%u}", call->unmarshall); + + switch (call->unmarshall) { + case 0: + afs_extract_to_tmp(call); + call->unmarshall++; + + /* extract the returned data length */ + case 1: + ret = afs_extract_data(call, true); + if (ret < 0) + return ret; + + size = call->count2 = ntohl(call->tmp); + size = round_up(size, 4); + + acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); + if (!acl) + return -ENOMEM; + call->reply[0] = acl; + acl->size = call->count2; + afs_extract_begin(call, acl->data, size); + call->unmarshall++; + + /* extract the returned data */ + case 2: + ret = afs_extract_data(call, true); + if (ret < 0) + return ret; + + afs_extract_to_buf(call, (21 + 6) * 4); + call->unmarshall++; + + /* extract the metadata */ + case 3: + ret = afs_extract_data(call, false); + if (ret < 0) + return ret; + + bp = call->buffer; + ret = afs_decode_status(call, &bp, &vnode->status, vnode, + &vnode->status.data_version, NULL); + if (ret < 0) + return ret; + xdr_decode_AFSVolSync(&bp, call->reply[2]); + + call->unmarshall++; + + case 4: + break; + } + + _leave(" = 0 [done]"); + return 0; +} + +static void afs_destroy_fs_fetch_acl(struct afs_call *call) +{ + kfree(call->reply[0]); + afs_flat_call_destructor(call); +} + +/* + * FS.FetchACL operation type + */ +static const struct afs_call_type afs_RXFSFetchACL = { + .name = "FS.FetchACL", + .op = afs_FS_FetchACL, + .deliver = afs_deliver_fs_fetch_acl, + .destructor = afs_destroy_fs_fetch_acl, +}; + +/* + * Fetch the ACL for a file. + */ +struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) +{ + struct afs_vnode *vnode = fc->vnode; + struct afs_call *call; + struct afs_net *net = afs_v2net(vnode); + __be32 *bp; + + _enter(",%x,{%llx:%llu},,", + key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); + + call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4); + if (!call) { + fc->ac.error = -ENOMEM; + return ERR_PTR(-ENOMEM); + } + + call->key = fc->key; + call->reply[0] = NULL; + call->reply[1] = vnode; + call->reply[2] = NULL; /* volsync */ + call->ret_reply0 = true; + + /* marshall the parameters */ + bp = call->request; + bp[0] = htonl(FSFETCHACL); + bp[1] = htonl(vnode->fid.vid); + bp[2] = htonl(vnode->fid.vnode); + bp[3] = htonl(vnode->fid.unique); + + call->cb_break = fc->cb_break; + afs_use_fs_server(call, fc->cbi); + trace_afs_make_fs_call(call, &vnode->fid); + afs_make_call(&fc->ac, call, GFP_KERNEL); + return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac); +} diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 585a5952f608..683b802c20ea 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -977,6 +977,13 @@ extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, struct afs_fid *, struct afs_file_status *, struct afs_callback *, struct afs_volsync *); +struct afs_acl { + u32 size; + u8 data[]; +}; + +extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *); + /* * fs_probe.c */ diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index e729ee3d4b02..b7d3d714d8ff 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c @@ -16,6 +16,7 @@ #include "internal.h" static const char afs_xattr_list[] = + "afs.acl\0" "afs.cell\0" "afs.fid\0" "afs.volume"; @@ -33,6 +34,57 @@ ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size) return sizeof(afs_xattr_list); } +/* + * Get a file's ACL. + */ +static int afs_xattr_get_acl(const struct xattr_handler *handler, + struct dentry *dentry, + struct inode *inode, const char *name, + void *buffer, size_t size) +{ + struct afs_fs_cursor fc; + struct afs_vnode *vnode = AFS_FS_I(inode); + struct afs_acl *acl = NULL; + struct key *key; + int ret; + + key = afs_request_key(vnode->volume->cell); + if (IS_ERR(key)) + return PTR_ERR(key); + + ret = -ERESTARTSYS; + if (afs_begin_vnode_operation(&fc, vnode, key)) { + while (afs_select_fileserver(&fc)) { + fc.cb_break = afs_calc_vnode_cb_break(vnode); + acl = afs_fs_fetch_acl(&fc); + } + + afs_check_for_remote_deletion(&fc, fc.vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break); + ret = afs_end_vnode_operation(&fc); + } + + if (ret == 0) { + ret = acl->size; + if (size > 0) { + ret = -ERANGE; + if (acl->size > size) + return -ERANGE; + memcpy(buffer, acl->data, acl->size); + ret = acl->size; + } + kfree(acl); + } + + key_put(key); + return ret; +} + +static const struct xattr_handler afs_xattr_afs_acl_handler = { + .name = "afs.acl", + .get = afs_xattr_get_acl, +}; + /* * Get the name of the cell on which a file resides. */ @@ -123,6 +175,7 @@ static const struct xattr_handler afs_xattr_afs_volume_handler = { }; const struct xattr_handler *afs_xattr_handlers[] = { + &afs_xattr_afs_acl_handler, &afs_xattr_afs_cell_handler, &afs_xattr_afs_fid_handler, &afs_xattr_afs_volume_handler, diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index f1373c29bf7d..25c2e089c6ea 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -33,6 +33,7 @@ enum afs_call_trace { enum afs_fs_operation { afs_FS_FetchData = 130, /* AFS Fetch file data */ + afs_FS_FetchACL = 131, /* AFS Fetch file ACL */ afs_FS_FetchStatus = 132, /* AFS Fetch file status */ afs_FS_StoreData = 133, /* AFS Store file data */ afs_FS_StoreStatus = 135, /* AFS Store file status */