aboutsummaryrefslogtreecommitdiffstats
path: root/fs/attr.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-10-08 11:06:08 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-10-08 11:06:08 -0400
commite55f1d1d13e7f1c364672d667d78fd1f640ab9f9 (patch)
tree406a3c127abb008f2f736c8d2ee03fc3c2926d6b /fs/attr.c
parentf334bcd94b7d3c0fbc34d518a86548f451ab5faf (diff)
parent030b533c4fd4d2ec3402363323de4bb2983c9cee (diff)
Merge remote-tracking branch 'jk/vfs' into work.misc
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 3c42cab06b5d..a19a64d41e7e 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
@@ -232,13 +245,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
232 if (!(ia_valid & ATTR_MTIME_SET)) 245 if (!(ia_valid & ATTR_MTIME_SET))
233 attr->ia_mtime = now; 246 attr->ia_mtime = now;
234 if (ia_valid & ATTR_KILL_PRIV) { 247 if (ia_valid & ATTR_KILL_PRIV) {
235 attr->ia_valid &= ~ATTR_KILL_PRIV;
236 ia_valid &= ~ATTR_KILL_PRIV;
237 error = security_inode_need_killpriv(dentry); 248 error = security_inode_need_killpriv(dentry);
238 if (error > 0) 249 if (error < 0)
239 error = security_inode_killpriv(dentry);
240 if (error)
241 return error; 250 return error;
251 if (error == 0)
252 ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV;
242 } 253 }
243 254
244 /* 255 /*