kernel: bump 4.4 to 4.4.167
[openwrt/openwrt.git] / target / linux / generic / patches-4.4 / 051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch
diff --git a/target/linux/generic/patches-4.4/051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch b/target/linux/generic/patches-4.4/051-0002-ovl-override-creds-with-the-ones-from-the-superblock.patch
deleted file mode 100644 (file)
index 2d40c7e..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-From 3fe6e52f062643676eb4518d68cee3bc1272091b Mon Sep 17 00:00:00 2001
-From: Antonio Murdaca <amurdaca@redhat.com>
-Date: Thu, 7 Apr 2016 15:48:25 +0200
-Subject: [PATCH] ovl: override creds with the ones from the superblock mounter
-
-In user namespace the whiteout creation fails with -EPERM because the
-current process isn't capable(CAP_SYS_ADMIN) when setting xattr.
-
-A simple reproducer:
-
-$ mkdir upper lower work merged lower/dir
-$ sudo mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged
-$ unshare -m -p -f -U -r bash
-
-Now as root in the user namespace:
-
-\# touch merged/dir/{1,2,3} # this will force a copy up of lower/dir
-\# rm -fR merged/*
-
-This ends up failing with -EPERM after the files in dir has been
-correctly deleted:
-
-unlinkat(4, "2", 0)                     = 0
-unlinkat(4, "1", 0)                     = 0
-unlinkat(4, "3", 0)                     = 0
-close(4)                                = 0
-unlinkat(AT_FDCWD, "merged/dir", AT_REMOVEDIR) = -1 EPERM (Operation not
-permitted)
-
-Interestingly, if you don't place files in merged/dir you can remove it,
-meaning if upper/dir does not exist, creating the char device file works
-properly in that same location.
-
-This patch uses ovl_sb_creator_cred() to get the cred struct from the
-superblock mounter and override the old cred with these new ones so that
-the whiteout creation is possible because overlay is wrong in assuming that
-the creds it will get with prepare_creds will be in the initial user
-namespace.  The old cap_raise game is removed in favor of just overriding
-the old cred struct.
-
-This patch also drops from ovl_copy_up_one() the following two lines:
-
-override_cred->fsuid = stat->uid;
-override_cred->fsgid = stat->gid;
-
-This is because the correct uid and gid are taken directly with the stat
-struct and correctly set with ovl_set_attr().
-
-Signed-off-by: Antonio Murdaca <runcom@redhat.com>
-Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
----
- fs/overlayfs/copy_up.c   | 26 +------------------
- fs/overlayfs/dir.c       | 67 ++++--------------------------------------------
- fs/overlayfs/overlayfs.h |  1 +
- fs/overlayfs/readdir.c   | 14 +++-------
- fs/overlayfs/super.c     | 18 ++++++++++++-
- 5 files changed, 27 insertions(+), 99 deletions(-)
-
---- a/fs/overlayfs/copy_up.c
-+++ b/fs/overlayfs/copy_up.c
-@@ -317,7 +317,6 @@ int ovl_copy_up_one(struct dentry *paren
-       struct dentry *upperdir;
-       struct dentry *upperdentry;
-       const struct cred *old_cred;
--      struct cred *override_cred;
-       char *link = NULL;
-       if (WARN_ON(!workdir))
-@@ -336,28 +335,7 @@ int ovl_copy_up_one(struct dentry *paren
-                       return PTR_ERR(link);
-       }
--      err = -ENOMEM;
--      override_cred = prepare_creds();
--      if (!override_cred)
--              goto out_free_link;
--
--      override_cred->fsuid = stat->uid;
--      override_cred->fsgid = stat->gid;
--      /*
--       * CAP_SYS_ADMIN for copying up extended attributes
--       * CAP_DAC_OVERRIDE for create
--       * CAP_FOWNER for chmod, timestamp update
--       * CAP_FSETID for chmod
--       * CAP_CHOWN for chown
--       * CAP_MKNOD for mknod
--       */
--      cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
--      cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
--      cap_raise(override_cred->cap_effective, CAP_FOWNER);
--      cap_raise(override_cred->cap_effective, CAP_FSETID);
--      cap_raise(override_cred->cap_effective, CAP_CHOWN);
--      cap_raise(override_cred->cap_effective, CAP_MKNOD);
--      old_cred = override_creds(override_cred);
-+      old_cred = ovl_override_creds(dentry->d_sb);
-       err = -EIO;
-       if (lock_rename(workdir, upperdir) != NULL) {
-@@ -380,9 +358,7 @@ int ovl_copy_up_one(struct dentry *paren
- out_unlock:
-       unlock_rename(workdir, upperdir);
-       revert_creds(old_cred);
--      put_cred(override_cred);
--out_free_link:
-       if (link)
-               free_page((unsigned long) link);
---- a/fs/overlayfs/dir.c
-+++ b/fs/overlayfs/dir.c
-@@ -408,28 +408,13 @@ static int ovl_create_or_link(struct den
-               err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
-       } else {
-               const struct cred *old_cred;
--              struct cred *override_cred;
--              err = -ENOMEM;
--              override_cred = prepare_creds();
--              if (!override_cred)
--                      goto out_iput;
--
--              /*
--               * CAP_SYS_ADMIN for setting opaque xattr
--               * CAP_DAC_OVERRIDE for create in workdir, rename
--               * CAP_FOWNER for removing whiteout from sticky dir
--               */
--              cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
--              cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
--              cap_raise(override_cred->cap_effective, CAP_FOWNER);
--              old_cred = override_creds(override_cred);
-+              old_cred = ovl_override_creds(dentry->d_sb);
-               err = ovl_create_over_whiteout(dentry, inode, &stat, link,
-                                              hardlink);
-               revert_creds(old_cred);
--              put_cred(override_cred);
-       }
-       if (!err)
-@@ -659,32 +644,11 @@ static int ovl_do_remove(struct dentry *
-       if (OVL_TYPE_PURE_UPPER(type)) {
-               err = ovl_remove_upper(dentry, is_dir);
-       } else {
--              const struct cred *old_cred;
--              struct cred *override_cred;
--
--              err = -ENOMEM;
--              override_cred = prepare_creds();
--              if (!override_cred)
--                      goto out_drop_write;
--
--              /*
--               * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
--               * CAP_DAC_OVERRIDE for create in workdir, rename
--               * CAP_FOWNER for removing whiteout from sticky dir
--               * CAP_FSETID for chmod of opaque dir
--               * CAP_CHOWN for chown of opaque dir
--               */
--              cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
--              cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
--              cap_raise(override_cred->cap_effective, CAP_FOWNER);
--              cap_raise(override_cred->cap_effective, CAP_FSETID);
--              cap_raise(override_cred->cap_effective, CAP_CHOWN);
--              old_cred = override_creds(override_cred);
-+              const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
-               err = ovl_remove_and_whiteout(dentry, is_dir);
-               revert_creds(old_cred);
--              put_cred(override_cred);
-       }
- out_drop_write:
-       ovl_drop_write(dentry);
-@@ -723,7 +687,6 @@ static int ovl_rename2(struct inode *old
-       bool new_is_dir = false;
-       struct dentry *opaquedir = NULL;
-       const struct cred *old_cred = NULL;
--      struct cred *override_cred = NULL;
-       err = -EINVAL;
-       if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
-@@ -792,26 +755,8 @@ static int ovl_rename2(struct inode *old
-       old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
-       new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
--      if (old_opaque || new_opaque) {
--              err = -ENOMEM;
--              override_cred = prepare_creds();
--              if (!override_cred)
--                      goto out_drop_write;
--
--              /*
--               * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
--               * CAP_DAC_OVERRIDE for create in workdir
--               * CAP_FOWNER for removing whiteout from sticky dir
--               * CAP_FSETID for chmod of opaque dir
--               * CAP_CHOWN for chown of opaque dir
--               */
--              cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
--              cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
--              cap_raise(override_cred->cap_effective, CAP_FOWNER);
--              cap_raise(override_cred->cap_effective, CAP_FSETID);
--              cap_raise(override_cred->cap_effective, CAP_CHOWN);
--              old_cred = override_creds(override_cred);
--      }
-+      if (old_opaque || new_opaque)
-+              old_cred = ovl_override_creds(old->d_sb);
-       if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
-               opaquedir = ovl_check_empty_and_clear(new);
-@@ -942,10 +887,8 @@ out_dput_old:
- out_unlock:
-       unlock_rename(new_upperdir, old_upperdir);
- out_revert_creds:
--      if (old_opaque || new_opaque) {
-+      if (old_opaque || new_opaque)
-               revert_creds(old_cred);
--              put_cred(override_cred);
--      }
- out_drop_write:
-       ovl_drop_write(old);
- out:
---- a/fs/overlayfs/overlayfs.h
-+++ b/fs/overlayfs/overlayfs.h
-@@ -150,6 +150,7 @@ void ovl_drop_write(struct dentry *dentr
- 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);
---- a/fs/overlayfs/readdir.c
-+++ b/fs/overlayfs/readdir.c
-@@ -36,6 +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,17 +207,8 @@ static int ovl_check_whiteouts(struct de
-       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);
-       if (!err) {
-@@ -232,7 +224,6 @@ static int ovl_check_whiteouts(struct de
-               mutex_unlock(&dir->d_inode->i_mutex);
-       }
-       revert_creds(old_cred);
--      put_cred(override_cred);
-       return err;
- }
-@@ -288,6 +279,7 @@ static int ovl_dir_read_merged(struct de
-       struct path realpath;
-       struct ovl_readdir_data rdd = {
-               .ctx.actor = ovl_fill_merge,
-+              .dentry = dentry,
-               .list = list,
-               .root = RB_ROOT,
-               .is_lowest = false,
---- a/fs/overlayfs/super.c
-+++ b/fs/overlayfs/super.c
-@@ -42,6 +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;
-@@ -246,6 +248,13 @@ bool ovl_is_whiteout(struct dentry *dent
-       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;
-@@ -587,6 +596,7 @@ static void ovl_put_super(struct super_b
-       kfree(ufs->config.lowerdir);
-       kfree(ufs->config.upperdir);
-       kfree(ufs->config.workdir);
-+      put_cred(ufs->creator_cred);
-       kfree(ufs);
- }
-@@ -1107,10 +1117,14 @@ static int ovl_fill_super(struct super_b
-       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)
-@@ -1143,6 +1157,8 @@ static int ovl_fill_super(struct super_b
- 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]);