]> Git Repo - linux.git/commitdiff
Merge tag 'ovl-update-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
authorLinus Torvalds <[email protected]>
Tue, 13 Dec 2022 04:18:26 +0000 (20:18 -0800)
committerLinus Torvalds <[email protected]>
Tue, 13 Dec 2022 04:18:26 +0000 (20:18 -0800)
Pull overlayfs update from Miklos Szeredi:

 - Fix a couple of bugs found by syzbot

 - Don't ingore some open flags set by fcntl(F_SETFL)

 - Fix failure to create a hard link in certain cases

 - Use type safe helpers for some mnt_userns transformations

 - Improve performance of mount

 - Misc cleanups

* tag 'ovl-update-6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: Kconfig: Fix spelling mistake "undelying" -> "underlying"
  ovl: use inode instead of dentry where possible
  ovl: Add comment on upperredirect reassignment
  ovl: use plain list filler in indexdir and workdir cleanup
  ovl: do not reconnect upper index records in ovl_indexdir_cleanup()
  ovl: fix comment typos
  ovl: port to vfs{g,u}id_t and associated helpers
  ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
  ovl: Use "buf" flexible array for memcpy() destination
  ovl: update ->f_iocb_flags when ovl_change_flags() modifies ->f_flags
  ovl: fix use inode directly in rcu-walk mode

1  2 
fs/overlayfs/dir.c
fs/overlayfs/file.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c

diff --combined fs/overlayfs/dir.c
index cbb569d5d234ae7557d9c6934c613344c587b477,c3032cef391ef0067072af787a7b35ca7b8a2337..f61e37f4c8ff4cbaea30826c4aea8fa0891140a8
@@@ -435,12 -435,28 +435,12 @@@ out
  }
  
  static int ovl_set_upper_acl(struct ovl_fs *ofs, struct dentry *upperdentry,
 -                           const char *name, const struct posix_acl *acl)
 +                           const char *acl_name, struct posix_acl *acl)
  {
 -      void *buffer;
 -      size_t size;
 -      int err;
 -
        if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !acl)
                return 0;
  
 -      size = posix_acl_xattr_size(acl->a_count);
 -      buffer = kmalloc(size, GFP_KERNEL);
 -      if (!buffer)
 -              return -ENOMEM;
 -
 -      err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
 -      if (err < 0)
 -              goto out_free;
 -
 -      err = ovl_do_setxattr(ofs, upperdentry, name, buffer, size, XATTR_CREATE);
 -out_free:
 -      kfree(buffer);
 -      return err;
 +      return ovl_do_set_acl(ofs, upperdentry, acl_name, acl);
  }
  
  static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
@@@ -576,28 -592,42 +576,42 @@@ static int ovl_create_or_link(struct de
                        goto out_revert_creds;
        }
  
-       err = -ENOMEM;
-       override_cred = prepare_creds();
-       if (override_cred) {
+       if (!attr->hardlink) {
+               err = -ENOMEM;
+               override_cred = prepare_creds();
+               if (!override_cred)
+                       goto out_revert_creds;
+               /*
+                * In the creation cases(create, mkdir, mknod, symlink),
+                * ovl should transfer current's fs{u,g}id to underlying
+                * fs. Because underlying fs want to initialize its new
+                * inode owner using current's fs{u,g}id. And in this
+                * case, the @inode is a new inode that is initialized
+                * in inode_init_owner() to current's fs{u,g}id. So use
+                * the inode's i_{u,g}id to override the cred's fs{u,g}id.
+                *
+                * But in the other hardlink case, ovl_link() does not
+                * create a new inode, so just use the ovl mounter's
+                * fs{u,g}id.
+                */
                override_cred->fsuid = inode->i_uid;
                override_cred->fsgid = inode->i_gid;
-               if (!attr->hardlink) {
-                       err = security_dentry_create_files_as(dentry,
-                                       attr->mode, &dentry->d_name, old_cred,
-                                       override_cred);
-                       if (err) {
-                               put_cred(override_cred);
-                               goto out_revert_creds;
-                       }
+               err = security_dentry_create_files_as(dentry,
+                               attr->mode, &dentry->d_name, old_cred,
+                               override_cred);
+               if (err) {
+                       put_cred(override_cred);
+                       goto out_revert_creds;
                }
                put_cred(override_creds(override_cred));
                put_cred(override_cred);
-               if (!ovl_dentry_is_whiteout(dentry))
-                       err = ovl_create_upper(dentry, inode, attr);
-               else
-                       err = ovl_create_over_whiteout(dentry, inode, attr);
        }
+       if (!ovl_dentry_is_whiteout(dentry))
+               err = ovl_create_upper(dentry, inode, attr);
+       else
+               err = ovl_create_over_whiteout(dentry, inode, attr);
  out_revert_creds:
        revert_creds(old_cred);
        return err;
@@@ -1295,9 -1325,7 +1309,9 @@@ const struct inode_operations ovl_dir_i
        .permission     = ovl_permission,
        .getattr        = ovl_getattr,
        .listxattr      = ovl_listxattr,
 +      .get_inode_acl  = ovl_get_inode_acl,
        .get_acl        = ovl_get_acl,
 +      .set_acl        = ovl_set_acl,
        .update_time    = ovl_update_time,
        .fileattr_get   = ovl_fileattr_get,
        .fileattr_set   = ovl_fileattr_set,
diff --combined fs/overlayfs/file.c
index d066be3b9226ec6ed557edd3772244842605db40,eadbe5e0dffdc17231abda41221239a6deb8af04..c9d0c362c7ef1136327c9a8faac3b2918a4f16c5
@@@ -34,7 -34,7 +34,7 @@@ static char ovl_whatisit(struct inode *
                return 'm';
  }
  
- /* No atime modificaton nor notify on underlying */
+ /* No atime modification nor notify on underlying */
  #define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
  
  static struct file *ovl_open_realfile(const struct file *file,
@@@ -96,6 -96,7 +96,7 @@@ static int ovl_change_flags(struct fil
  
        spin_lock(&file->f_lock);
        file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
+       file->f_iocb_flags = iocb_flags(file);
        spin_unlock(&file->f_lock);
  
        return 0;
@@@ -517,16 -518,9 +518,16 @@@ static long ovl_fallocate(struct file *
        const struct cred *old_cred;
        int ret;
  
 +      inode_lock(inode);
 +      /* Update mode */
 +      ovl_copyattr(inode);
 +      ret = file_remove_privs(file);
 +      if (ret)
 +              goto out_unlock;
 +
        ret = ovl_real_fdget(file, &real);
        if (ret)
 -              return ret;
 +              goto out_unlock;
  
        old_cred = ovl_override_creds(file_inode(file)->i_sb);
        ret = vfs_fallocate(real.file, mode, offset, len);
  
        fdput(real);
  
 +out_unlock:
 +      inode_unlock(inode);
 +
        return ret;
  }
  
@@@ -577,23 -568,14 +578,23 @@@ static loff_t ovl_copyfile(struct file 
        const struct cred *old_cred;
        loff_t ret;
  
 +      inode_lock(inode_out);
 +      if (op != OVL_DEDUPE) {
 +              /* Update mode */
 +              ovl_copyattr(inode_out);
 +              ret = file_remove_privs(file_out);
 +              if (ret)
 +                      goto out_unlock;
 +      }
 +
        ret = ovl_real_fdget(file_out, &real_out);
        if (ret)
 -              return ret;
 +              goto out_unlock;
  
        ret = ovl_real_fdget(file_in, &real_in);
        if (ret) {
                fdput(real_out);
 -              return ret;
 +              goto out_unlock;
        }
  
        old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
        fdput(real_in);
        fdput(real_out);
  
 +out_unlock:
 +      inode_unlock(inode_out);
 +
        return ret;
  }
  
diff --combined fs/overlayfs/overlayfs.h
index 480e6aabef27a8052bcf906738c05b0d1e24a799,0b07a9ef7e5bb405b21d41aaab4f5c3afc2f20a8..1df7f850ff3bb2a0d9af356cbd4beaa4cb59a4a5
@@@ -8,8 -8,6 +8,8 @@@
  #include <linux/uuid.h>
  #include <linux/fs.h>
  #include <linux/namei.h>
 +#include <linux/posix_acl.h>
 +#include <linux/posix_acl_xattr.h>
  #include "ovl_entry.h"
  
  #undef pr_fmt
@@@ -110,7 -108,7 +110,7 @@@ struct ovl_fh 
        u8 padding[3];  /* make sure fb.fid is 32bit aligned */
        union {
                struct ovl_fb fb;
-               u8 buf[0];
+               DECLARE_FLEX_ARRAY(u8, buf);
        };
  } __packed;
  
@@@ -280,18 -278,6 +280,18 @@@ static inline int ovl_removexattr(struc
        return ovl_do_removexattr(ofs, dentry, ovl_xattr(ofs, ox));
  }
  
 +static inline int ovl_do_set_acl(struct ovl_fs *ofs, struct dentry *dentry,
 +                               const char *acl_name, struct posix_acl *acl)
 +{
 +      return vfs_set_acl(ovl_upper_mnt_userns(ofs), dentry, acl_name, acl);
 +}
 +
 +static inline int ovl_do_remove_acl(struct ovl_fs *ofs, struct dentry *dentry,
 +                                  const char *acl_name)
 +{
 +      return vfs_remove_acl(ovl_upper_mnt_userns(ofs), dentry, acl_name);
 +}
 +
  static inline int ovl_do_rename(struct ovl_fs *ofs, struct inode *olddir,
                                struct dentry *olddentry, struct inode *newdir,
                                struct dentry *newdentry, unsigned int flags)
@@@ -415,7 -401,7 +415,7 @@@ const char *ovl_dentry_get_redirect(str
  void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect);
  void ovl_inode_update(struct inode *inode, struct dentry *upperdentry);
  void ovl_dir_modified(struct dentry *dentry, bool impurity);
- u64 ovl_dentry_version_get(struct dentry *dentry);
+ u64 ovl_inode_version_get(struct inode *inode);
  bool ovl_is_whiteout(struct dentry *dentry);
  struct file *ovl_path_open(const struct path *path, int flags);
  int ovl_copy_up_start(struct dentry *dentry, int flags);
@@@ -539,7 -525,8 +539,8 @@@ int ovl_check_origin_fh(struct ovl_fs *
  int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
                      enum ovl_xattr ox, struct dentry *real, bool is_upper,
                      bool set);
- struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index);
+ struct dentry *ovl_index_upper(struct ovl_fs *ofs, struct dentry *index,
+                              bool connected);
  int ovl_verify_index(struct ovl_fs *ofs, struct dentry *index);
  int ovl_get_index_name(struct ovl_fs *ofs, struct dentry *origin,
                       struct qstr *name);
@@@ -584,9 -571,9 +585,9 @@@ int ovl_indexdir_cleanup(struct ovl_fs 
   * lower dir was removed under it and possibly before it was rotated from upper
   * to lower layer.
   */
- static inline bool ovl_dir_is_real(struct dentry *dir)
+ static inline bool ovl_dir_is_real(struct inode *dir)
  {
-       return !ovl_test_flag(OVL_WHITEOUTS, d_inode(dir));
+       return !ovl_test_flag(OVL_WHITEOUTS, dir);
  }
  
  /* inode.c */
@@@ -608,33 -595,9 +609,33 @@@ int ovl_xattr_get(struct dentry *dentry
  ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
  
  #ifdef CONFIG_FS_POSIX_ACL
 -struct posix_acl *ovl_get_acl(struct inode *inode, int type, bool rcu);
 +struct posix_acl *do_ovl_get_acl(struct user_namespace *mnt_userns,
 +                               struct inode *inode, int type,
 +                               bool rcu, bool noperm);
 +static inline struct posix_acl *ovl_get_inode_acl(struct inode *inode, int type,
 +                                                bool rcu)
 +{
 +      return do_ovl_get_acl(&init_user_ns, inode, type, rcu, true);
 +}
 +static inline struct posix_acl *ovl_get_acl(struct user_namespace *mnt_userns,
 +                                          struct dentry *dentry, int type)
 +{
 +      return do_ovl_get_acl(mnt_userns, d_inode(dentry), type, false, false);
 +}
 +int ovl_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
 +              struct posix_acl *acl, int type);
 +struct posix_acl *ovl_get_acl_path(const struct path *path,
 +                                 const char *acl_name, bool noperm);
  #else
 -#define ovl_get_acl   NULL
 +#define ovl_get_inode_acl     NULL
 +#define ovl_get_acl           NULL
 +#define ovl_set_acl           NULL
 +static inline struct posix_acl *ovl_get_acl_path(const struct path *path,
 +                                               const char *acl_name,
 +                                               bool noperm)
 +{
 +      return NULL;
 +}
  #endif
  
  int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags);
diff --combined fs/overlayfs/super.c
index 2addafe4e14a4637b902a1cb82bcd901e33c2948,3d14a3f1465d1c2a4751371a7ad19bb2aabd7e17..85b891152a2ca0fd786bcd8bbab8b5beed97ab33
@@@ -139,11 -139,16 +139,16 @@@ static int ovl_dentry_revalidate_common
                                        unsigned int flags, bool weak)
  {
        struct ovl_entry *oe = dentry->d_fsdata;
+       struct inode *inode = d_inode_rcu(dentry);
        struct dentry *upper;
        unsigned int i;
        int ret = 1;
  
-       upper = ovl_dentry_upper(dentry);
+       /* Careful in RCU mode */
+       if (!inode)
+               return -ECHILD;
+       upper = ovl_i_dentry_upper(inode);
        if (upper)
                ret = ovl_revalidate_real(upper, flags, weak);
  
@@@ -813,11 -818,13 +818,11 @@@ retry
                 * allowed as upper are limited to "normal" ones, where checking
                 * for the above two errors is sufficient.
                 */
 -              err = ovl_do_removexattr(ofs, work,
 -                                       XATTR_NAME_POSIX_ACL_DEFAULT);
 +              err = ovl_do_remove_acl(ofs, work, XATTR_NAME_POSIX_ACL_DEFAULT);
                if (err && err != -ENODATA && err != -EOPNOTSUPP)
                        goto out_dput;
  
 -              err = ovl_do_removexattr(ofs, work,
 -                                       XATTR_NAME_POSIX_ACL_ACCESS);
 +              err = ovl_do_remove_acl(ofs, work, XATTR_NAME_POSIX_ACL_ACCESS);
                if (err && err != -ENODATA && err != -EOPNOTSUPP)
                        goto out_dput;
  
@@@ -999,6 -1006,83 +1004,6 @@@ static unsigned int ovl_split_lowerdirs
        return ctr;
  }
  
 -static int __maybe_unused
 -ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
 -                      struct dentry *dentry, struct inode *inode,
 -                      const char *name, void *buffer, size_t size)
 -{
 -      return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
 -}
 -
 -static int __maybe_unused
 -ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
 -                      struct user_namespace *mnt_userns,
 -                      struct dentry *dentry, struct inode *inode,
 -                      const char *name, const void *value,
 -                      size_t size, int flags)
 -{
 -      struct dentry *workdir = ovl_workdir(dentry);
 -      struct inode *realinode = ovl_inode_real(inode);
 -      struct posix_acl *acl = NULL;
 -      int err;
 -
 -      /* Check that everything is OK before copy-up */
 -      if (value) {
 -              /* The above comment can be understood in two ways:
 -               *
 -               * 1. We just want to check whether the basic POSIX ACL format
 -               *    is ok. For example, if the header is correct and the size
 -               *    is sane.
 -               * 2. We want to know whether the ACL_{GROUP,USER} entries can
 -               *    be mapped according to the underlying filesystem.
 -               *
 -               * Currently, we only check 1. If we wanted to check 2. we
 -               * would need to pass the mnt_userns and the fs_userns of the
 -               * underlying filesystem. But frankly, I think checking 1. is
 -               * enough to start the copy-up.
 -               */
 -              acl = vfs_set_acl_prepare(&init_user_ns, &init_user_ns, value, size);
 -              if (IS_ERR(acl))
 -                      return PTR_ERR(acl);
 -      }
 -      err = -EOPNOTSUPP;
 -      if (!IS_POSIXACL(d_inode(workdir)))
 -              goto out_acl_release;
 -      if (!realinode->i_op->set_acl)
 -              goto out_acl_release;
 -      if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) {
 -              err = acl ? -EACCES : 0;
 -              goto out_acl_release;
 -      }
 -      err = -EPERM;
 -      if (!inode_owner_or_capable(&init_user_ns, inode))
 -              goto out_acl_release;
 -
 -      posix_acl_release(acl);
 -
 -      /*
 -       * Check if sgid bit needs to be cleared (actual setacl operation will
 -       * be done with mounter's capabilities and so that won't do it for us).
 -       */
 -      if (unlikely(inode->i_mode & S_ISGID) &&
 -          handler->flags == ACL_TYPE_ACCESS &&
 -          !in_group_p(inode->i_gid) &&
 -          !capable_wrt_inode_uidgid(&init_user_ns, inode, CAP_FSETID)) {
 -              struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
 -
 -              err = ovl_setattr(&init_user_ns, dentry, &iattr);
 -              if (err)
 -                      return err;
 -      }
 -
 -      err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
 -      return err;
 -
 -out_acl_release:
 -      posix_acl_release(acl);
 -      return err;
 -}
 -
  static int ovl_own_xattr_get(const struct xattr_handler *handler,
                             struct dentry *dentry, struct inode *inode,
                             const char *name, void *buffer, size_t size)
@@@ -1031,6 -1115,22 +1036,6 @@@ static int ovl_other_xattr_set(const st
        return ovl_xattr_set(dentry, inode, name, value, size, flags);
  }
  
 -static const struct xattr_handler __maybe_unused
 -ovl_posix_acl_access_xattr_handler = {
 -      .name = XATTR_NAME_POSIX_ACL_ACCESS,
 -      .flags = ACL_TYPE_ACCESS,
 -      .get = ovl_posix_acl_xattr_get,
 -      .set = ovl_posix_acl_xattr_set,
 -};
 -
 -static const struct xattr_handler __maybe_unused
 -ovl_posix_acl_default_xattr_handler = {
 -      .name = XATTR_NAME_POSIX_ACL_DEFAULT,
 -      .flags = ACL_TYPE_DEFAULT,
 -      .get = ovl_posix_acl_xattr_get,
 -      .set = ovl_posix_acl_xattr_set,
 -};
 -
  static const struct xattr_handler ovl_own_trusted_xattr_handler = {
        .prefix = OVL_XATTR_TRUSTED_PREFIX,
        .get = ovl_own_xattr_get,
@@@ -1051,8 -1151,8 +1056,8 @@@ static const struct xattr_handler ovl_o
  
  static const struct xattr_handler *ovl_trusted_xattr_handlers[] = {
  #ifdef CONFIG_FS_POSIX_ACL
 -      &ovl_posix_acl_access_xattr_handler,
 -      &ovl_posix_acl_default_xattr_handler,
 +      &posix_acl_access_xattr_handler,
 +      &posix_acl_default_xattr_handler,
  #endif
        &ovl_own_trusted_xattr_handler,
        &ovl_other_xattr_handler,
  
  static const struct xattr_handler *ovl_user_xattr_handlers[] = {
  #ifdef CONFIG_FS_POSIX_ACL
 -      &ovl_posix_acl_access_xattr_handler,
 -      &ovl_posix_acl_default_xattr_handler,
 +      &posix_acl_access_xattr_handler,
 +      &posix_acl_default_xattr_handler,
  #endif
        &ovl_own_user_xattr_handler,
        &ovl_other_xattr_handler,
This page took 0.072959 seconds and 4 git commands to generate.