From aba5c92061e5978fb4eb9b926c985e0a734c597e Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Thu, 21 Jan 2016 11:52:04 -0600 Subject: [PATCH 5/6] overlayfs: Be more careful about copying up sxid files When an overlayfs filesystem's lowerdir is on a nosuid filesystem but the upperdir is not, it's possible to copy up an sxid file or stick directory into upperdir without changing the mode by opening the file rw in the overlayfs mount without writing to it. This makes it possible to bypass the nosuid restriction on the lowerdir mount. It's a bad idea in general to let the mounter copy up a sxid file if the mounter wouldn't have had permission to create the sxid file in the first place. Therefore change ovl_set_xattr to exclude these bits when initially setting the mode, then set the full mode after setting the user for the inode. This allows copy up for non-sxid files to work as before but causes copy up to fail for the cases where the user could not have created the sxid inode in upperdir. Signed-off-by: Seth Forshee --- fs/overlayfs/copy_up.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index fc3afd3..4c5649a 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -172,10 +172,19 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat) { int err = 0; + /* + * For the most part we want to set the mode bits before setting + * the user, otherwise the current context might lack permission + * for setting the mode. However for sxid/sticky bits we want + * the operation to fail if the current user isn't privileged + * towards the resulting inode. So we first set the mode but + * exclude the sxid/sticky bits, then set the user, then set the + * mode again if any of the sxid/sticky bits are set. + */ if (!S_ISLNK(stat->mode)) { struct iattr attr = { .ia_valid = ATTR_MODE, - .ia_mode = stat->mode, + .ia_mode = stat->mode & ~(S_ISUID|S_ISGID|S_ISVTX), }; err = notify_change(upperdentry, &attr, NULL); } @@ -187,6 +196,14 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat) }; err = notify_change(upperdentry, &attr, NULL); } + if (!err && !S_ISLNK(stat->mode) && + (stat->mode & (S_ISUID|S_ISGID|S_ISVTX))) { + struct iattr attr = { + .ia_valid = ATTR_MODE, + .ia_mode = stat->mode, + }; + err = notify_change(upperdentry, &attr, NULL); + } if (!err) ovl_set_timestamps(upperdentry, stat); -- 2.7.0.rc3