]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/overlayfs/copy_up.c
ovl: during copy up, switch to mounter's creds early
[linux.git] / fs / overlayfs / copy_up.c
index 54e5d6681786780812c9a5adddc27dd782b40bbb..796d06fafd0919c380c54a9c1d6f80f07e5c1b8a 100644 (file)
@@ -57,6 +57,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
        ssize_t list_size, size, value_size = 0;
        char *buf, *name, *value = NULL;
        int uninitialized_var(error);
+       size_t slen;
 
        if (!old->d_inode->i_op->getxattr ||
            !new->d_inode->i_op->getxattr)
@@ -79,7 +80,18 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
                goto out;
        }
 
-       for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
+       for (name = buf; list_size; name += slen) {
+               slen = strnlen(name, list_size) + 1;
+
+               /* underlying fs providing us with an broken xattr list? */
+               if (WARN_ON(slen > list_size)) {
+                       error = -EIO;
+                       break;
+               }
+               list_size -= slen;
+
+               if (ovl_is_private_xattr(name))
+                       continue;
 retry:
                size = vfs_getxattr(old, name, value, value_size);
                if (size == -ERANGE)
@@ -336,7 +348,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
        struct path parentpath;
        struct dentry *upperdir;
        struct dentry *upperdentry;
-       const struct cred *old_cred;
        char *link = NULL;
 
        if (WARN_ON(!workdir))
@@ -357,8 +368,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
                        return PTR_ERR(link);
        }
 
-       old_cred = ovl_override_creds(dentry->d_sb);
-
        err = -EIO;
        if (lock_rename(workdir, upperdir) != NULL) {
                pr_err("overlayfs: failed to lock workdir+upperdir\n");
@@ -379,7 +388,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
        }
 out_unlock:
        unlock_rename(workdir, upperdir);
-       revert_creds(old_cred);
 
        if (link)
                free_page((unsigned long) link);
@@ -389,9 +397,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
 
 int ovl_copy_up(struct dentry *dentry)
 {
-       int err;
+       int err = 0;
+       const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
 
-       err = 0;
        while (!err) {
                struct dentry *next;
                struct dentry *parent;
@@ -423,6 +431,7 @@ int ovl_copy_up(struct dentry *dentry)
                dput(parent);
                dput(next);
        }
+       revert_creds(old_cred);
 
        return err;
 }