]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
ovl: fix sgid on directory
authorMiklos Szeredi <mszeredi@redhat.com>
Fri, 29 Jul 2016 10:05:23 +0000 (12:05 +0200)
committerShan Hai <shan.hai@oracle.com>
Fri, 4 Aug 2017 05:49:51 +0000 (13:49 +0800)
When creating directory in workdir, the group/sgid inheritance from the
parent dir was omitted completely.  Fix this by calling inode_init_owner()
on overlay inode and using the resulting uid/gid/mode to create the file.

Unfortunately the sgid bit can be stripped off due to umask, so need to
reset the mode in this case in workdir before moving the directory in
place.

Reported-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Orabug: 26401569

(backport upstream commit bb0d2b8ad29630b580ac903f989e704e23462357)

Signed-off-by: Shan Hai <shan.hai@oracle.com>
Reviewed-by: Somasundaram Krishnasamy <somasundaram.krishnasamy@oracle.com>
fs/overlayfs/dir.c

index 378c715b7e1fd8edc3555dfcbdc2b29e444d9435..0413d72f79fbcf8b2b4685c3fb8aa017397848fe 100644 (file)
@@ -357,6 +357,21 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
        if (err)
                goto out_dput2;
 
+       /*
+        * mode could have been mutilated due to umask (e.g. sgid directory)
+        */
+       if (!S_ISLNK(stat->mode) && newdentry->d_inode->i_mode != stat->mode) {
+               struct iattr attr = {
+                       .ia_valid = ATTR_MODE,
+                       .ia_mode = stat->mode,
+               };
+               inode_lock(newdentry->d_inode);
+               err = notify_change(newdentry, &attr, NULL);
+               inode_unlock(newdentry->d_inode);
+               if (err)
+                       goto out_cleanup;
+       }
+
        if (S_ISDIR(stat->mode)) {
                err = ovl_set_opaque(newdentry);
                if (err)
@@ -397,7 +412,6 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
        const struct cred *old_cred;
        struct cred *override_cred;
        struct kstat stat = {
-               .mode = mode,
                .rdev = rdev,
        };
 
@@ -410,12 +424,15 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
        if (err)
                goto out_iput;
 
+       inode_init_owner(inode, dentry->d_parent->d_inode, mode);
+       stat.mode = inode->i_mode;
+
        old_cred = ovl_override_creds(dentry->d_sb);
        err = -ENOMEM;
        override_cred = prepare_creds();
        if (override_cred) {
-               override_cred->fsuid = old_cred->fsuid;
-               override_cred->fsgid = old_cred->fsgid;
+               override_cred->fsuid = inode->i_uid;
+               override_cred->fsgid = inode->i_gid;
                put_cred(override_creds(override_cred));
                put_cred(override_cred);
 
@@ -427,8 +444,14 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
                                                        link, hardlink);
        }
        revert_creds(old_cred);
-       if (!err)
+       if (!err) {
+               struct inode *realinode = d_inode(ovl_dentry_upper(dentry));
+
+               WARN_ON(inode->i_mode != realinode->i_mode);
+               WARN_ON(!uid_eq(inode->i_uid, realinode->i_uid));
+               WARN_ON(!gid_eq(inode->i_gid, realinode->i_gid));
                inode = NULL;
+       }
 out_iput:
        iput(inode);
 out: