From 1ec95bf34d976b38897d1977b155a544d77b05e7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 23 Jul 2011 02:28:13 -0400 Subject: 9p: close ACL leaks Signed-off-by: Al Viro --- fs/9p/acl.c | 22 +++++++++++++--------- fs/9p/acl.h | 6 +++--- fs/9p/vfs_inode_dotl.c | 9 ++++++--- 3 files changed, 22 insertions(+), 15 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/acl.c b/fs/9p/acl.c index e98f56d3787..7350f53f3b5 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -185,12 +185,15 @@ int v9fs_acl_chmod(struct dentry *dentry) } int v9fs_set_create_acl(struct dentry *dentry, - struct posix_acl *dpacl, struct posix_acl *pacl) + struct posix_acl **dpacl, struct posix_acl **pacl) { - v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl); - v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl); - posix_acl_release(dpacl); - posix_acl_release(pacl); + if (dentry) { + v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, *dpacl); + v9fs_set_acl(dentry, ACL_TYPE_ACCESS, *pacl); + } + posix_acl_release(*dpacl); + posix_acl_release(*pacl); + *dpacl = *pacl = NULL; return 0; } @@ -212,11 +215,11 @@ int v9fs_acl_mode(struct inode *dir, mode_t *modep, struct posix_acl *clone; if (S_ISDIR(mode)) - *dpacl = acl; + *dpacl = posix_acl_dup(acl); clone = posix_acl_clone(acl, GFP_NOFS); - retval = -ENOMEM; + posix_acl_release(acl); if (!clone) - goto cleanup; + return -ENOMEM; retval = posix_acl_create_masq(clone, &mode); if (retval < 0) { @@ -225,11 +228,12 @@ int v9fs_acl_mode(struct inode *dir, mode_t *modep, } if (retval > 0) *pacl = clone; + else + posix_acl_release(clone); } *modep = mode; return 0; cleanup: - posix_acl_release(acl); return retval; } diff --git a/fs/9p/acl.h b/fs/9p/acl.h index 59e18c2e8c7..3eba10f3af1 100644 --- a/fs/9p/acl.h +++ b/fs/9p/acl.h @@ -19,7 +19,7 @@ extern int v9fs_get_acl(struct inode *, struct p9_fid *); extern int v9fs_check_acl(struct inode *inode, int mask); extern int v9fs_acl_chmod(struct dentry *); extern int v9fs_set_create_acl(struct dentry *, - struct posix_acl *, struct posix_acl *); + struct posix_acl **, struct posix_acl **); extern int v9fs_acl_mode(struct inode *dir, mode_t *modep, struct posix_acl **dpacl, struct posix_acl **pacl); #else @@ -33,8 +33,8 @@ static inline int v9fs_acl_chmod(struct dentry *dentry) return 0; } static inline int v9fs_set_create_acl(struct dentry *dentry, - struct posix_acl *dpacl, - struct posix_acl *pacl) + struct posix_acl **dpacl, + struct posix_acl **pacl) { return 0; } diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 32bbbe5aa68..803f59ff2fa 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -242,7 +242,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, goto error; /* Now set the ACL based on the default value */ - v9fs_set_create_acl(dentry, dacl, pacl); + v9fs_set_create_acl(dentry, &dacl, &pacl); v9inode = V9FS_I(inode); mutex_lock(&v9inode->v_mutex); @@ -283,6 +283,7 @@ error: err_clunk_old_fid: if (ofid) p9_client_clunk(ofid); + v9fs_set_create_acl(NULL, &dacl, &pacl); return err; } @@ -376,12 +377,13 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, d_instantiate(dentry, inode); } /* Now set the ACL based on the default value */ - v9fs_set_create_acl(dentry, dacl, pacl); + v9fs_set_create_acl(dentry, &dacl, &pacl); inc_nlink(dir); v9fs_invalidate_inode_attr(dir); error: if (fid) p9_client_clunk(fid); + v9fs_set_create_acl(NULL, &dacl, &pacl); return err; } @@ -781,10 +783,11 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, d_instantiate(dentry, inode); } /* Now set the ACL based on the default value */ - v9fs_set_create_acl(dentry, dacl, pacl); + v9fs_set_create_acl(dentry, &dacl, &pacl); error: if (fid) p9_client_clunk(fid); + v9fs_set_create_acl(NULL, &dacl, &pacl); return err; } -- cgit v1.2.3-18-g5258 From e77819e57f0817c6dc7cadd061acd70c604cbce2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 22 Jul 2011 19:30:19 -0700 Subject: vfs: move ACL cache lookup into generic code This moves logic for checking the cached ACL values from low-level filesystems into generic code. The end result is a streamlined ACL check that doesn't need to load the inode->i_op->check_acl pointer at all for the common cached case. The filesystems also don't need to check for a non-blocking RCU walk case in their acl_check() functions, because that is all handled at a VFS layer. Signed-off-by: Linus Torvalds Signed-off-by: Al Viro --- fs/9p/acl.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 7350f53f3b5..8be87857605 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -101,9 +101,6 @@ int v9fs_check_acl(struct inode *inode, int mask) struct posix_acl *acl; struct v9fs_session_info *v9ses; - if (mask & MAY_NOT_BLOCK) - return -ECHILD; - v9ses = v9fs_inode2v9ses(inode); if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) || ((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) { -- cgit v1.2.3-18-g5258 From ebbb0ef2871bf3f529987313a9146cc42419a8a8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 23 Jul 2011 17:36:38 +0200 Subject: 9p: do no return 0 from ->check_acl without actually checking If we do not want to use ACLs we at least need to perform normal Unix permission checks. From the comment I'm not quite sure that's what is intended, but if 0p wants to do permission checks entirely on the server it needs to do so in ->permission, not in ->check_acl. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/9p/acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/9p') diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 8be87857605..df4d7a171d7 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -108,7 +108,7 @@ int v9fs_check_acl(struct inode *inode, int mask) * On access = client and acl = on mode get the acl * values from the server */ - return 0; + return -EAGAIN; } acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); -- cgit v1.2.3-18-g5258 From bc26ab5f65ae41b71df86ea46df3c3833d1d8d83 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 23 Jul 2011 00:18:02 -0400 Subject: kill boilerplate around posix_acl_chmod_masq() new helper: posix_acl_chmod(&acl, gfp, mode). Replaces acl with modified clone or with NULL if that has failed; returns 0 or -ve on error. All callers of posix_acl_chmod_masq() switched to that - they'd been doing exactly the same thing. Signed-off-by: Al Viro --- fs/9p/acl.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/acl.c b/fs/9p/acl.c index df4d7a171d7..d7211e28c0d 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -162,21 +162,18 @@ err_free_out: int v9fs_acl_chmod(struct dentry *dentry) { int retval = 0; - struct posix_acl *acl, *clone; + struct posix_acl *acl; struct inode *inode = dentry->d_inode; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); if (acl) { - clone = posix_acl_clone(acl, GFP_KERNEL); + retval = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); + if (retval) + return retval; + retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, acl); posix_acl_release(acl); - if (!clone) - return -ENOMEM; - retval = posix_acl_chmod_masq(clone, inode->i_mode); - if (!retval) - retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone); - posix_acl_release(clone); } return retval; } -- cgit v1.2.3-18-g5258 From 826cae2f2b4d726b925f43bc208a571639da4761 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 23 Jul 2011 03:10:32 -0400 Subject: kill boilerplates around posix_acl_create_masq() new helper: posix_acl_create(&acl, gfp, mode_p). Replaces acl with modified clone, on failure releases acl and replaces with NULL. Returns 0 or -ve on error. All callers of posix_acl_create_masq() switched. Signed-off-by: Al Viro --- fs/9p/acl.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/acl.c b/fs/9p/acl.c index d7211e28c0d..075bc909da1 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -206,30 +206,18 @@ int v9fs_acl_mode(struct inode *dir, mode_t *modep, mode &= ~current_umask(); } if (acl) { - struct posix_acl *clone; - if (S_ISDIR(mode)) *dpacl = posix_acl_dup(acl); - clone = posix_acl_clone(acl, GFP_NOFS); - posix_acl_release(acl); - if (!clone) - return -ENOMEM; - - retval = posix_acl_create_masq(clone, &mode); - if (retval < 0) { - posix_acl_release(clone); - goto cleanup; - } + retval = posix_acl_create(&acl, GFP_NOFS, &mode); + if (retval < 0) + return retval; if (retval > 0) - *pacl = clone; + *pacl = acl; else - posix_acl_release(clone); + posix_acl_release(acl); } *modep = mode; return 0; -cleanup: - return retval; - } static int v9fs_remote_get_acl(struct dentry *dentry, const char *name, -- cgit v1.2.3-18-g5258 From 4e34e719e457f2e031297175410fc0bd4016a085 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 23 Jul 2011 17:37:31 +0200 Subject: fs: take the ACL checks to common code Replace the ->check_acl method with a ->get_acl method that simply reads an ACL from disk after having a cache miss. This means we can replace the ACL checking boilerplate code with a single implementation in namei.c. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/9p/acl.c | 14 +++----------- fs/9p/acl.h | 4 ++-- fs/9p/vfs_inode_dotl.c | 4 ++-- 3 files changed, 7 insertions(+), 15 deletions(-) (limited to 'fs/9p') diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 075bc909da1..814be079c18 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c @@ -96,7 +96,7 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) return acl; } -int v9fs_check_acl(struct inode *inode, int mask) +struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type) { struct posix_acl *acl; struct v9fs_session_info *v9ses; @@ -108,18 +108,10 @@ int v9fs_check_acl(struct inode *inode, int mask) * On access = client and acl = on mode get the acl * values from the server */ - return -EAGAIN; + return NULL; } - acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); + return v9fs_get_cached_acl(inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - int error = posix_acl_permission(inode, acl, mask); - posix_acl_release(acl); - return error; - } - return -EAGAIN; } static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl) diff --git a/fs/9p/acl.h b/fs/9p/acl.h index 3eba10f3af1..ddb7ae19d97 100644 --- a/fs/9p/acl.h +++ b/fs/9p/acl.h @@ -16,14 +16,14 @@ #ifdef CONFIG_9P_FS_POSIX_ACL extern int v9fs_get_acl(struct inode *, struct p9_fid *); -extern int v9fs_check_acl(struct inode *inode, int mask); +extern struct posix_acl *v9fs_iop_get_acl(struct inode *inode, int type); extern int v9fs_acl_chmod(struct dentry *); extern int v9fs_set_create_acl(struct dentry *, struct posix_acl **, struct posix_acl **); extern int v9fs_acl_mode(struct inode *dir, mode_t *modep, struct posix_acl **dpacl, struct posix_acl **pacl); #else -#define v9fs_check_acl NULL +#define v9fs_iop_get_acl NULL static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) { return 0; diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 803f59ff2fa..9d808d0e0cd 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -872,7 +872,7 @@ const struct inode_operations v9fs_dir_inode_operations_dotl = { .getxattr = generic_getxattr, .removexattr = generic_removexattr, .listxattr = v9fs_listxattr, - .check_acl = v9fs_check_acl, + .get_acl = v9fs_iop_get_acl, }; const struct inode_operations v9fs_file_inode_operations_dotl = { @@ -882,7 +882,7 @@ const struct inode_operations v9fs_file_inode_operations_dotl = { .getxattr = generic_getxattr, .removexattr = generic_removexattr, .listxattr = v9fs_listxattr, - .check_acl = v9fs_check_acl, + .get_acl = v9fs_iop_get_acl, }; const struct inode_operations v9fs_symlink_inode_operations_dotl = { -- cgit v1.2.3-18-g5258