diff options
author | Christoph Hellwig <hch@lst.de> | 2010-06-04 05:30:04 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-08-09 16:47:39 -0400 |
commit | 2c27c65ed0696f0b5df2dad2cf6462d72164d547 (patch) | |
tree | 7d9036e3dea98938f7fd7074366ee73929e9b2e5 /fs/attr.c | |
parent | db78b877f7744bec4a9d9f9e7d10da3931d7cd39 (diff) |
check ATTR_SIZE contraints in inode_change_ok
Make sure we check the truncate constraints early on in ->setattr by adding
those checks to inode_change_ok. Also clean up and document inode_change_ok
to make this obvious.
As a fallout we don't have to call inode_newsize_ok from simple_setsize and
simplify it down to a truncate_setsize which doesn't return an error. This
simplifies a lot of setattr implementations and means we use truncate_setsize
almost everywhere. Get rid of fat_setsize now that it's trivial and mark
ext2_setsize static to make the calling convention obvious.
Keep the inode_newsize_ok in vmtruncate for now as all callers need an
audit for its removal anyway.
Note: setattr code in ecryptfs doesn't call inode_change_ok at all and
needs a deeper audit, but that is left for later.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/attr.c')
-rw-r--r-- | fs/attr.c | 44 |
1 files changed, 30 insertions, 14 deletions
@@ -14,35 +14,53 @@ | |||
14 | #include <linux/fcntl.h> | 14 | #include <linux/fcntl.h> |
15 | #include <linux/security.h> | 15 | #include <linux/security.h> |
16 | 16 | ||
17 | /* Taken over from the old code... */ | 17 | /** |
18 | 18 | * inode_change_ok - check if attribute changes to an inode are allowed | |
19 | /* POSIX UID/GID verification for setting inode attributes. */ | 19 | * @inode: inode to check |
20 | * @attr: attributes to change | ||
21 | * | ||
22 | * Check if we are allowed to change the attributes contained in @attr | ||
23 | * in the given inode. This includes the normal unix access permission | ||
24 | * checks, as well as checks for rlimits and others. | ||
25 | * | ||
26 | * Should be called as the first thing in ->setattr implementations, | ||
27 | * possibly after taking additional locks. | ||
28 | */ | ||
20 | int inode_change_ok(const struct inode *inode, struct iattr *attr) | 29 | int inode_change_ok(const struct inode *inode, struct iattr *attr) |
21 | { | 30 | { |
22 | int retval = -EPERM; | ||
23 | unsigned int ia_valid = attr->ia_valid; | 31 | unsigned int ia_valid = attr->ia_valid; |
24 | 32 | ||
33 | /* | ||
34 | * First check size constraints. These can't be overriden using | ||
35 | * ATTR_FORCE. | ||
36 | */ | ||
37 | if (ia_valid & ATTR_SIZE) { | ||
38 | int error = inode_newsize_ok(inode, attr->ia_size); | ||
39 | if (error) | ||
40 | return error; | ||
41 | } | ||
42 | |||
25 | /* If force is set do it anyway. */ | 43 | /* If force is set do it anyway. */ |
26 | if (ia_valid & ATTR_FORCE) | 44 | if (ia_valid & ATTR_FORCE) |
27 | goto fine; | 45 | return 0; |
28 | 46 | ||
29 | /* Make sure a caller can chown. */ | 47 | /* Make sure a caller can chown. */ |
30 | if ((ia_valid & ATTR_UID) && | 48 | if ((ia_valid & ATTR_UID) && |
31 | (current_fsuid() != inode->i_uid || | 49 | (current_fsuid() != inode->i_uid || |
32 | attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) | 50 | attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) |
33 | goto error; | 51 | return -EPERM; |
34 | 52 | ||
35 | /* Make sure caller can chgrp. */ | 53 | /* Make sure caller can chgrp. */ |
36 | if ((ia_valid & ATTR_GID) && | 54 | if ((ia_valid & ATTR_GID) && |
37 | (current_fsuid() != inode->i_uid || | 55 | (current_fsuid() != inode->i_uid || |
38 | (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && | 56 | (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && |
39 | !capable(CAP_CHOWN)) | 57 | !capable(CAP_CHOWN)) |
40 | goto error; | 58 | return -EPERM; |
41 | 59 | ||
42 | /* Make sure a caller can chmod. */ | 60 | /* Make sure a caller can chmod. */ |
43 | if (ia_valid & ATTR_MODE) { | 61 | if (ia_valid & ATTR_MODE) { |
44 | if (!is_owner_or_cap(inode)) | 62 | if (!is_owner_or_cap(inode)) |
45 | goto error; | 63 | return -EPERM; |
46 | /* Also check the setgid bit! */ | 64 | /* Also check the setgid bit! */ |
47 | if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : | 65 | if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : |
48 | inode->i_gid) && !capable(CAP_FSETID)) | 66 | inode->i_gid) && !capable(CAP_FSETID)) |
@@ -52,12 +70,10 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) | |||
52 | /* Check for setting the inode time. */ | 70 | /* Check for setting the inode time. */ |
53 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) { | 71 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) { |
54 | if (!is_owner_or_cap(inode)) | 72 | if (!is_owner_or_cap(inode)) |
55 | goto error; | 73 | return -EPERM; |
56 | } | 74 | } |
57 | fine: | 75 | |
58 | retval = 0; | 76 | return 0; |
59 | error: | ||
60 | return retval; | ||
61 | } | 77 | } |
62 | EXPORT_SYMBOL(inode_change_ok); | 78 | EXPORT_SYMBOL(inode_change_ok); |
63 | 79 | ||
@@ -113,7 +129,7 @@ EXPORT_SYMBOL(inode_newsize_ok); | |||
113 | * | 129 | * |
114 | * setattr_copy updates the inode's metadata with that specified | 130 | * setattr_copy updates the inode's metadata with that specified |
115 | * in attr. Noticably missing is inode size update, which is more complex | 131 | * in attr. Noticably missing is inode size update, which is more complex |
116 | * as it requires pagecache updates. See simple_setsize. | 132 | * as it requires pagecache updates. |
117 | * | 133 | * |
118 | * The inode is not marked as dirty after this operation. The rationale is | 134 | * The inode is not marked as dirty after this operation. The rationale is |
119 | * that for "simple" filesystems, the struct inode is the inode storage. | 135 | * that for "simple" filesystems, the struct inode is the inode storage. |