aboutsummaryrefslogtreecommitdiffstats
path: root/fs/attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/attr.c')
-rw-r--r--fs/attr.c35
1 files changed, 23 insertions, 12 deletions
diff --git a/fs/attr.c b/fs/attr.c
index 6530ced19697..ee697ddc6c2e 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -17,19 +17,22 @@
17#include <linux/ima.h> 17#include <linux/ima.h>
18 18
19/** 19/**
20 * inode_change_ok - check if attribute changes to an inode are allowed 20 * setattr_prepare - check if attribute changes to a dentry are allowed
21 * @inode: inode to check 21 * @dentry: dentry to check
22 * @attr: attributes to change 22 * @attr: attributes to change
23 * 23 *
24 * Check if we are allowed to change the attributes contained in @attr 24 * Check if we are allowed to change the attributes contained in @attr
25 * in the given inode. This includes the normal unix access permission 25 * in the given dentry. This includes the normal unix access permission
26 * checks, as well as checks for rlimits and others. 26 * checks, as well as checks for rlimits and others. The function also clears
27 * SGID bit from mode if user is not allowed to set it. Also file capabilities
28 * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
27 * 29 *
28 * Should be called as the first thing in ->setattr implementations, 30 * Should be called as the first thing in ->setattr implementations,
29 * possibly after taking additional locks. 31 * possibly after taking additional locks.
30 */ 32 */
31int inode_change_ok(const struct inode *inode, struct iattr *attr) 33int setattr_prepare(struct dentry *dentry, struct iattr *attr)
32{ 34{
35 struct inode *inode = d_inode(dentry);
33 unsigned int ia_valid = attr->ia_valid; 36 unsigned int ia_valid = attr->ia_valid;
34 37
35 /* 38 /*
@@ -44,7 +47,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
44 47
45 /* If force is set do it anyway. */ 48 /* If force is set do it anyway. */
46 if (ia_valid & ATTR_FORCE) 49 if (ia_valid & ATTR_FORCE)
47 return 0; 50 goto kill_priv;
48 51
49 /* Make sure a caller can chown. */ 52 /* Make sure a caller can chown. */
50 if ((ia_valid & ATTR_UID) && 53 if ((ia_valid & ATTR_UID) &&
@@ -77,9 +80,19 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
77 return -EPERM; 80 return -EPERM;
78 } 81 }
79 82
83kill_priv:
84 /* User has permission for the change */
85 if (ia_valid & ATTR_KILL_PRIV) {
86 int error;
87
88 error = security_inode_killpriv(dentry);
89 if (error)
90 return error;
91 }
92
80 return 0; 93 return 0;
81} 94}
82EXPORT_SYMBOL(inode_change_ok); 95EXPORT_SYMBOL(setattr_prepare);
83 96
84/** 97/**
85 * inode_newsize_ok - may this inode be truncated to a given size 98 * inode_newsize_ok - may this inode be truncated to a given size
@@ -217,13 +230,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
217 if (!(ia_valid & ATTR_MTIME_SET)) 230 if (!(ia_valid & ATTR_MTIME_SET))
218 attr->ia_mtime = now; 231 attr->ia_mtime = now;
219 if (ia_valid & ATTR_KILL_PRIV) { 232 if (ia_valid & ATTR_KILL_PRIV) {
220 attr->ia_valid &= ~ATTR_KILL_PRIV;
221 ia_valid &= ~ATTR_KILL_PRIV;
222 error = security_inode_need_killpriv(dentry); 233 error = security_inode_need_killpriv(dentry);
223 if (error > 0) 234 if (error < 0)
224 error = security_inode_killpriv(dentry);
225 if (error)
226 return error; 235 return error;
236 if (error == 0)
237 ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
227 } 238 }
228 239
229 /* 240 /*