diff options
Diffstat (limited to 'fs/attr.c')
| -rw-r--r-- | fs/attr.c | 26 | 
1 files changed, 20 insertions, 6 deletions
| diff --git a/fs/attr.c b/fs/attr.c index 66899b6e9bd8..dbe996b0dedf 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -61,9 +61,15 @@ static bool chgrp_ok(struct user_namespace *mnt_userns,  		     const struct inode *inode, kgid_t gid)  {  	kgid_t kgid = i_gid_into_mnt(mnt_userns, inode); -	if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)) && -	    (in_group_p(gid) || gid_eq(gid, inode->i_gid))) -		return true; +	if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode))) { +		kgid_t mapped_gid; + +		if (gid_eq(gid, inode->i_gid)) +			return true; +		mapped_gid = mapped_kgid_fs(mnt_userns, i_user_ns(inode), gid); +		if (in_group_p(mapped_gid)) +			return true; +	}  	if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))  		return true;  	if (gid_eq(kgid, INVALID_GID) && @@ -123,12 +129,20 @@ int setattr_prepare(struct user_namespace *mnt_userns, struct dentry *dentry,  	/* Make sure a caller can chmod. */  	if (ia_valid & ATTR_MODE) { +		kgid_t mapped_gid; +  		if (!inode_owner_or_capable(mnt_userns, inode))  			return -EPERM; + +		if (ia_valid & ATTR_GID) +			mapped_gid = mapped_kgid_fs(mnt_userns, +						i_user_ns(inode), attr->ia_gid); +		else +			mapped_gid = i_gid_into_mnt(mnt_userns, inode); +  		/* Also check the setgid bit! */ -               if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : -                                i_gid_into_mnt(mnt_userns, inode)) && -                    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID)) +		if (!in_group_p(mapped_gid) && +		    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))  			attr->ia_mode &= ~S_ISGID;  	} |