]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
UBUNTU: SAUCE: overlayfs: Be more careful about copying up sxid files
authorSeth Forshee <seth.forshee@canonical.com>
Thu, 21 Jan 2016 17:52:04 +0000 (11:52 -0600)
committerSeth Forshee <seth.forshee@canonical.com>
Tue, 5 Sep 2017 12:33:19 +0000 (07:33 -0500)
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.

BugLink: http://bugs.launchpad.net/bugs/1534961
BugLink: http://bugs.launchpad.net/bugs/1535150
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: Leann Ogasawara <leann.ogasawara@canonical.com>
fs/overlayfs/copy_up.c

index acb6f97deb97ccd25c7a3b785f1ae1280858d6c4..55e3bd9b2df6b91d7c12a19ce8c9649cddab71e3 100644 (file)
@@ -212,10 +212,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);
        }
@@ -227,6 +236,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);