diff options
author | Serge E. Hallyn <serge.hallyn@canonical.com> | 2011-07-26 18:58:27 +0000 |
---|---|---|
committer | Eric W. Biederman <ebiederm@aristanetworks.com> | 2011-08-11 10:07:51 -0500 |
commit | a3e1c336c2f555197ee86b60bb742636eb60e24c (patch) | |
tree | e5a4c4de64398d54e01a480d3201ef8901eca014 | |
parent | ec3d61047307d8ec0fb66dd2eb575240215bb00b (diff) | |
download | linux-user-ns-devel-a3e1c336c2f555197ee86b60bb742636eb60e24c.tar.gz |
user_ns: convert fs/attr.c to targeted capabilities
Signed-off-by: Serge E. Hallyn <serge.hallyn@canonical.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r-- | fs/attr.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/fs/attr.c b/fs/attr.c index 538e27959d3f7..e0cf46a008d76 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -29,6 +29,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) { unsigned int ia_valid = attr->ia_valid; + struct user_namespace *ns; /* * First check size constraints. These can't be overriden using @@ -44,26 +45,28 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) if (ia_valid & ATTR_FORCE) return 0; + ns = inode_userns(inode); /* Make sure a caller can chown. */ if ((ia_valid & ATTR_UID) && - (current_fsuid() != inode->i_uid || - attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) + (ns != current_user_ns() || current_fsuid() != inode->i_uid || + attr->ia_uid != inode->i_uid) && !ns_capable(ns, CAP_CHOWN)) return -EPERM; /* Make sure caller can chgrp. */ if ((ia_valid & ATTR_GID) && - (current_fsuid() != inode->i_uid || + (ns != current_user_ns() || current_fsuid() != inode->i_uid || (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && - !capable(CAP_CHOWN)) + !ns_capable(ns, CAP_CHOWN)) return -EPERM; /* Make sure a caller can chmod. */ if (ia_valid & ATTR_MODE) { + gid_t gid = (ia_valid & ATTR_GID) ? attr->ia_gid : inode->i_gid; if (!inode_owner_or_capable(inode)) return -EPERM; /* Also check the setgid bit! */ - if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : - inode->i_gid) && !capable(CAP_FSETID)) + if ((ns != current_user_ns() || !in_group_p(gid)) && + !ns_capable(ns, CAP_FSETID)) attr->ia_mode &= ~S_ISGID; } @@ -154,9 +157,12 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) inode->i_sb->s_time_gran); if (ia_valid & ATTR_MODE) { umode_t mode = attr->ia_mode; + struct user_namespace *ns = inode_userns(inode); - if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) + if ((ns != current_user_ns() || !in_group_p(inode->i_gid)) && + !ns_capable(ns, CAP_FSETID)) mode &= ~S_ISGID; + inode->i_mode = mode; } } |