Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszer...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 27 May 2016 23:44:39 +0000 (16:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 27 May 2016 23:44:39 +0000 (16:44 -0700)
Pull overlayfs update from Miklos Szeredi:
 "The meat of this is a change to use the mounter's credentials for
  operations that require elevated privileges (such as whiteout
  creation).  This fixes behavior under user namespaces as well as being
  a nice cleanup"

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: Do d_type check only if work dir creation was successful
  ovl: update documentation
  ovl: override creds with the ones from the superblock mounter

1  2 
fs/overlayfs/overlayfs.h
fs/overlayfs/readdir.c
fs/overlayfs/super.c

diff --combined fs/overlayfs/overlayfs.h
index 99ec4b0352371f47202a793c350b1e09d846c798,4cebeb24c08d74a10d3ec711962e06e3d1919cb9..724f5fcb4e249314ab2359b221c3c4fd56cd3d74
@@@ -153,6 -153,7 +153,7 @@@ void ovl_drop_write(struct dentry *dent
  bool ovl_dentry_is_opaque(struct dentry *dentry);
  void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
  bool ovl_is_whiteout(struct dentry *dentry);
+ const struct cred *ovl_override_creds(struct super_block *sb);
  void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
  struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                          unsigned int flags);
@@@ -173,8 -174,8 +174,8 @@@ int ovl_setattr(struct dentry *dentry, 
  int ovl_permission(struct inode *inode, int mask);
  int ovl_setxattr(struct dentry *dentry, const char *name,
                 const void *value, size_t size, int flags);
 -ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
 -                   void *value, size_t size);
 +ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode,
 +                   const char *name, void *value, size_t size);
  ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
  int ovl_removexattr(struct dentry *dentry, const char *name);
  struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags);
diff --combined fs/overlayfs/readdir.c
index da186ee4f846820703fa1a2fffb290c876991f1e,e9206bc8598f3f31d7f1f8752505fb32b359b889..d11ae826bcbc94215abc441a4c1d53434691e5c4
@@@ -36,6 -36,7 +36,7 @@@ struct ovl_dir_cache 
  
  struct ovl_readdir_data {
        struct dir_context ctx;
+       struct dentry *dentry;
        bool is_lowest;
        struct rb_root root;
        struct list_head *list;
@@@ -206,21 -207,10 +207,12 @@@ static int ovl_check_whiteouts(struct d
        struct ovl_cache_entry *p;
        struct dentry *dentry;
        const struct cred *old_cred;
-       struct cred *override_cred;
-       override_cred = prepare_creds();
-       if (!override_cred)
-               return -ENOMEM;
  
-       /*
-        * CAP_DAC_OVERRIDE for lookup
-        */
-       cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
-       old_cred = override_creds(override_cred);
+       old_cred = ovl_override_creds(rdd->dentry->d_sb);
  
 -      err = mutex_lock_killable(&dir->d_inode->i_mutex);
 +      inode_lock(dir->d_inode);
 +      err = 0;
 +      // XXX: err = mutex_lock_killable(&dir->d_inode->i_mutex);
        if (!err) {
                while (rdd->first_maybe_whiteout) {
                        p = rdd->first_maybe_whiteout;
                inode_unlock(dir->d_inode);
        }
        revert_creds(old_cred);
-       put_cred(override_cred);
  
        return err;
  }
@@@ -290,6 -279,7 +281,7 @@@ static int ovl_dir_read_merged(struct d
        struct path realpath;
        struct ovl_readdir_data rdd = {
                .ctx.actor = ovl_fill_merge,
+               .dentry = dentry,
                .list = list,
                .root = RB_ROOT,
                .is_lowest = false,
diff --combined fs/overlayfs/super.c
index ed53ae0fe86881ea3578320e880cc561b113b459,781e1d86d2ce6a8eef2116ced61d2fd97e51ed34..ce02f46029da7c3aa7c69be9291d62c81baeb642
@@@ -42,6 -42,8 +42,8 @@@ struct ovl_fs 
        long lower_namelen;
        /* pathnames of lower and upper dirs, for show_options */
        struct ovl_config config;
+       /* creds of process who forced instantiation of super block */
+       const struct cred *creator_cred;
  };
  
  struct ovl_dir_cache;
@@@ -265,6 -267,13 +267,13 @@@ bool ovl_is_whiteout(struct dentry *den
        return inode && IS_WHITEOUT(inode);
  }
  
+ const struct cred *ovl_override_creds(struct super_block *sb)
+ {
+       struct ovl_fs *ofs = sb->s_fs_info;
+       return override_creds(ofs->creator_cred);
+ }
  static bool ovl_is_opaquedir(struct dentry *dentry)
  {
        int res;
        if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr)
                return false;
  
 -      res = inode->i_op->getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
 +      res = inode->i_op->getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
        if (res == 1 && val == 'y')
                return true;
  
@@@ -603,6 -612,7 +612,7 @@@ static void ovl_put_super(struct super_
        kfree(ufs->config.lowerdir);
        kfree(ufs->config.upperdir);
        kfree(ufs->config.workdir);
+       put_cred(ufs->creator_cred);
        kfree(ufs);
  }
  
@@@ -1064,16 -1074,19 +1074,19 @@@ static int ovl_fill_super(struct super_
                /*
                 * Upper should support d_type, else whiteouts are visible.
                 * Given workdir and upper are on same fs, we can do
-                * iterate_dir() on workdir.
+                * iterate_dir() on workdir. This check requires successful
+                * creation of workdir in previous step.
                 */
-               err = ovl_check_d_type_supported(&workpath);
-               if (err < 0)
-                       goto out_put_workdir;
+               if (ufs->workdir) {
+                       err = ovl_check_d_type_supported(&workpath);
+                       if (err < 0)
+                               goto out_put_workdir;
  
-               if (!err) {
-                       pr_err("overlayfs: upper fs needs to support d_type.\n");
-                       err = -EINVAL;
-                       goto out_put_workdir;
+                       if (!err) {
+                               pr_err("overlayfs: upper fs needs to support d_type.\n");
+                               err = -EINVAL;
+                               goto out_put_workdir;
+                       }
                }
        }
  
        else
                sb->s_d_op = &ovl_dentry_operations;
  
+       ufs->creator_cred = prepare_creds();
+       if (!ufs->creator_cred)
+               goto out_put_lower_mnt;
        err = -ENOMEM;
        oe = ovl_alloc_entry(numlower);
        if (!oe)
-               goto out_put_lower_mnt;
+               goto out_put_cred;
  
        root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
        if (!root_dentry)
  
  out_free_oe:
        kfree(oe);
+ out_put_cred:
+       put_cred(ufs->creator_cred);
  out_put_lower_mnt:
        for (i = 0; i < ufs->numlower; i++)
                mntput(ufs->lower_mnt[i]);
This page took 0.031781 seconds and 5 git commands to generate.