summaryrefslogtreecommitdiffstats
path: root/fs/attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/attr.c')
-rw-r--r--fs/attr.c36
1 files changed, 28 insertions, 8 deletions
diff --git a/fs/attr.c b/fs/attr.c
index 12ffdb6fb63c..d0b4d34878fb 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -18,6 +18,32 @@
18#include <linux/evm.h> 18#include <linux/evm.h>
19#include <linux/ima.h> 19#include <linux/ima.h>
20 20
21static bool chown_ok(const struct inode *inode, kuid_t uid)
22{
23 if (uid_eq(current_fsuid(), inode->i_uid) &&
24 uid_eq(uid, inode->i_uid))
25 return true;
26 if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
27 return true;
28 if (uid_eq(inode->i_uid, INVALID_UID) &&
29 ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
30 return true;
31 return false;
32}
33
34static bool chgrp_ok(const struct inode *inode, kgid_t gid)
35{
36 if (uid_eq(current_fsuid(), inode->i_uid) &&
37 (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
38 return true;
39 if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
40 return true;
41 if (gid_eq(inode->i_gid, INVALID_GID) &&
42 ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
43 return true;
44 return false;
45}
46
21/** 47/**
22 * setattr_prepare - check if attribute changes to a dentry are allowed 48 * setattr_prepare - check if attribute changes to a dentry are allowed
23 * @dentry: dentry to check 49 * @dentry: dentry to check
@@ -52,17 +78,11 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
52 goto kill_priv; 78 goto kill_priv;
53 79
54 /* Make sure a caller can chown. */ 80 /* Make sure a caller can chown. */
55 if ((ia_valid & ATTR_UID) && 81 if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid))
56 (!uid_eq(current_fsuid(), inode->i_uid) ||
57 !uid_eq(attr->ia_uid, inode->i_uid)) &&
58 !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
59 return -EPERM; 82 return -EPERM;
60 83
61 /* Make sure caller can chgrp. */ 84 /* Make sure caller can chgrp. */
62 if ((ia_valid & ATTR_GID) && 85 if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid))
63 (!uid_eq(current_fsuid(), inode->i_uid) ||
64 (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
65 !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
66 return -EPERM; 86 return -EPERM;
67 87
68 /* Make sure a caller can chmod. */ 88 /* Make sure a caller can chmod. */