Merge branch 'work.xattr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[cascardo/linux.git] / fs / overlayfs / copy_up.c
index 43fdc27..3f803b3 100644 (file)
@@ -58,8 +58,8 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
        char *buf, *name, *value = NULL;
        int uninitialized_var(error);
 
-       if (!old->d_inode->i_op->getxattr ||
-           !new->d_inode->i_op->getxattr)
+       if (!(old->d_inode->i_opflags & IOP_XATTR) ||
+           !(new->d_inode->i_opflags & IOP_XATTR))
                return 0;
 
        list_size = vfs_listxattr(old, NULL, 0);
@@ -105,6 +105,13 @@ retry:
                        goto retry;
                }
 
+               error = security_inode_copy_up_xattr(name);
+               if (error < 0 && error != -EOPNOTSUPP)
+                       break;
+               if (error == 1) {
+                       error = 0;
+                       continue; /* Discard */
+               }
                error = vfs_setxattr(new, name, value, size, 0);
                if (error)
                        break;
@@ -248,6 +255,8 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
        struct dentry *upper = NULL;
        umode_t mode = stat->mode;
        int err;
+       const struct cred *old_creds = NULL;
+       struct cred *new_creds = NULL;
 
        newdentry = ovl_lookup_temp(workdir, dentry);
        err = PTR_ERR(newdentry);
@@ -260,10 +269,23 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
        if (IS_ERR(upper))
                goto out1;
 
+       err = security_inode_copy_up(dentry, &new_creds);
+       if (err < 0)
+               goto out2;
+
+       if (new_creds)
+               old_creds = override_creds(new_creds);
+
        /* Can't properly set mode on creation because of the umask */
        stat->mode &= S_IFMT;
        err = ovl_create_real(wdir, newdentry, stat, link, NULL, true);
        stat->mode = mode;
+
+       if (new_creds) {
+               revert_creds(old_creds);
+               put_cred(new_creds);
+       }
+
        if (err)
                goto out2;