]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge tag 'pull-f_path' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Oct 2025 23:32:36 +0000 (16:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Oct 2025 23:32:36 +0000 (16:32 -0700)
Pull file->f_path constification from Al Viro:
 "Only one thing was modifying ->f_path of an opened file - acct(2).

  Massaging that away and constifying a bunch of struct path * arguments
  in functions that might be given &file->f_path ends up with the
  situation where we can turn ->f_path into an anon union of const
  struct path f_path and struct path __f_path, the latter modified only
  in a few places in fs/{file_table,open,namei}.c, all for struct file
  instances that are yet to be opened"

* tag 'pull-f_path' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (23 commits)
  Have cc(1) catch attempts to modify ->f_path
  kernel/acct.c: saner struct file treatment
  configfs:get_target() - release path as soon as we grab configfs_item reference
  apparmor/af_unix: constify struct path * arguments
  ovl_is_real_file: constify realpath argument
  ovl_sync_file(): constify path argument
  ovl_lower_dir(): constify path argument
  ovl_get_verity_digest(): constify path argument
  ovl_validate_verity(): constify {meta,data}path arguments
  ovl_ensure_verity_loaded(): constify datapath argument
  ksmbd_vfs_set_init_posix_acl(): constify path argument
  ksmbd_vfs_inherit_posix_acl(): constify path argument
  ksmbd_vfs_kern_path_unlock(): constify path argument
  ksmbd_vfs_path_lookup_locked(): root_share_path can be const struct path *
  check_export(): constify path argument
  export_operations->open(): constify path argument
  rqst_exp_get_by_name(): constify path argument
  nfs: constify path argument of __vfs_getattr()
  bpf...d_path(): constify path argument
  done_path_create(): constify path argument
  ...

16 files changed:
1  2 
fs/internal.h
fs/namei.c
fs/nfs/localio.c
fs/nsfs.c
fs/open.c
fs/overlayfs/copy_up.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/pidfs.c
fs/smb/server/vfs.c
include/linux/exportfs.h
include/linux/fs.h
include/linux/namei.h
kernel/trace/bpf_trace.c
tools/testing/selftests/bpf/bpf_experimental.h

diff --cc fs/internal.h
Simple merge
diff --cc fs/namei.c
index 507ca0d7878d6a26445574f227e39c6475dea88c,ba8bf73d2f9cfd80e518cbc354df821ffe981995..7377020a2cba02501483020e0fc93c279fb38d3e
@@@ -4254,9 -4168,9 +4254,9 @@@ struct dentry *start_creating_path(int 
        putname(filename);
        return res;
  }
 -EXPORT_SYMBOL(kern_path_create);
 +EXPORT_SYMBOL(start_creating_path);
  
- void end_creating_path(struct path *path, struct dentry *dentry)
 -void done_path_create(const struct path *path, struct dentry *dentry)
++void end_creating_path(const struct path *path, struct dentry *dentry)
  {
        if (!IS_ERR(dentry))
                dput(dentry);
Simple merge
diff --cc fs/nsfs.c
index e7fd8a790aaa4b4b46d422e99eedc8f24def865c,59aa801347a7de7fc2ff4d04516381ecf1dfd2aa..648dc59bef7f2456f963f0c55c38a36102c3141b
+++ b/fs/nsfs.c
@@@ -432,157 -415,6 +432,157 @@@ static const struct stashed_operations 
        .put_data = nsfs_put_data,
  };
  
- static struct file *nsfs_export_open(struct path *path, unsigned int oflags)
 +#define NSFS_FID_SIZE_U32_VER0 (NSFS_FILE_HANDLE_SIZE_VER0 / sizeof(u32))
 +#define NSFS_FID_SIZE_U32_LATEST (NSFS_FILE_HANDLE_SIZE_LATEST / sizeof(u32))
 +
 +static int nsfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
 +                        struct inode *parent)
 +{
 +      struct nsfs_file_handle *fid = (struct nsfs_file_handle *)fh;
 +      struct ns_common *ns = inode->i_private;
 +      int len = *max_len;
 +
 +      if (parent)
 +              return FILEID_INVALID;
 +
 +      if (len < NSFS_FID_SIZE_U32_VER0) {
 +              *max_len = NSFS_FID_SIZE_U32_LATEST;
 +              return FILEID_INVALID;
 +      } else if (len > NSFS_FID_SIZE_U32_LATEST) {
 +              *max_len = NSFS_FID_SIZE_U32_LATEST;
 +      }
 +
 +      fid->ns_id      = ns->ns_id;
 +      fid->ns_type    = ns->ns_type;
 +      fid->ns_inum    = inode->i_ino;
 +      return FILEID_NSFS;
 +}
 +
 +static struct dentry *nsfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
 +                                      int fh_len, int fh_type)
 +{
 +      struct path path __free(path_put) = {};
 +      struct nsfs_file_handle *fid = (struct nsfs_file_handle *)fh;
 +      struct user_namespace *owning_ns = NULL;
 +      struct ns_common *ns;
 +      int ret;
 +
 +      if (fh_len < NSFS_FID_SIZE_U32_VER0)
 +              return NULL;
 +
 +      /* Check that any trailing bytes are zero. */
 +      if ((fh_len > NSFS_FID_SIZE_U32_LATEST) &&
 +          memchr_inv((void *)fid + NSFS_FID_SIZE_U32_LATEST, 0,
 +                     fh_len - NSFS_FID_SIZE_U32_LATEST))
 +              return NULL;
 +
 +      switch (fh_type) {
 +      case FILEID_NSFS:
 +              break;
 +      default:
 +              return NULL;
 +      }
 +
 +      scoped_guard(rcu) {
 +              ns = ns_tree_lookup_rcu(fid->ns_id, fid->ns_type);
 +              if (!ns)
 +                      return NULL;
 +
 +              VFS_WARN_ON_ONCE(ns->ns_id != fid->ns_id);
 +              VFS_WARN_ON_ONCE(ns->ns_type != fid->ns_type);
 +              VFS_WARN_ON_ONCE(ns->inum != fid->ns_inum);
 +
 +              if (!__ns_ref_get(ns))
 +                      return NULL;
 +      }
 +
 +      switch (ns->ns_type) {
 +#ifdef CONFIG_CGROUPS
 +      case CLONE_NEWCGROUP:
 +              if (!current_in_namespace(to_cg_ns(ns)))
 +                      owning_ns = to_cg_ns(ns)->user_ns;
 +              break;
 +#endif
 +#ifdef CONFIG_IPC_NS
 +      case CLONE_NEWIPC:
 +              if (!current_in_namespace(to_ipc_ns(ns)))
 +                      owning_ns = to_ipc_ns(ns)->user_ns;
 +              break;
 +#endif
 +      case CLONE_NEWNS:
 +              if (!current_in_namespace(to_mnt_ns(ns)))
 +                      owning_ns = to_mnt_ns(ns)->user_ns;
 +              break;
 +#ifdef CONFIG_NET_NS
 +      case CLONE_NEWNET:
 +              if (!current_in_namespace(to_net_ns(ns)))
 +                      owning_ns = to_net_ns(ns)->user_ns;
 +              break;
 +#endif
 +#ifdef CONFIG_PID_NS
 +      case CLONE_NEWPID:
 +              if (!current_in_namespace(to_pid_ns(ns))) {
 +                      owning_ns = to_pid_ns(ns)->user_ns;
 +              } else if (!READ_ONCE(to_pid_ns(ns)->child_reaper)) {
 +                      ns->ops->put(ns);
 +                      return ERR_PTR(-EPERM);
 +              }
 +              break;
 +#endif
 +#ifdef CONFIG_TIME_NS
 +      case CLONE_NEWTIME:
 +              if (!current_in_namespace(to_time_ns(ns)))
 +                      owning_ns = to_time_ns(ns)->user_ns;
 +              break;
 +#endif
 +#ifdef CONFIG_USER_NS
 +      case CLONE_NEWUSER:
 +              if (!current_in_namespace(to_user_ns(ns)))
 +                      owning_ns = to_user_ns(ns);
 +              break;
 +#endif
 +#ifdef CONFIG_UTS_NS
 +      case CLONE_NEWUTS:
 +              if (!current_in_namespace(to_uts_ns(ns)))
 +                      owning_ns = to_uts_ns(ns)->user_ns;
 +              break;
 +#endif
 +      default:
 +              return ERR_PTR(-EOPNOTSUPP);
 +      }
 +
 +      if (owning_ns && !ns_capable(owning_ns, CAP_SYS_ADMIN)) {
 +              ns->ops->put(ns);
 +              return ERR_PTR(-EPERM);
 +      }
 +
 +      /* path_from_stashed() unconditionally consumes the reference. */
 +      ret = path_from_stashed(&ns->stashed, nsfs_mnt, ns, &path);
 +      if (ret)
 +              return ERR_PTR(ret);
 +
 +      return no_free_ptr(path.dentry);
 +}
 +
 +static int nsfs_export_permission(struct handle_to_path_ctx *ctx,
 +                                 unsigned int oflags)
 +{
 +      /* nsfs_fh_to_dentry() performs all permission checks. */
 +      return 0;
 +}
 +
++static struct file *nsfs_export_open(const struct path *path, unsigned int oflags)
 +{
 +      return file_open_root(path, "", oflags, 0);
 +}
 +
 +static const struct export_operations nsfs_export_operations = {
 +      .encode_fh      = nsfs_encode_fh,
 +      .fh_to_dentry   = nsfs_fh_to_dentry,
 +      .open           = nsfs_export_open,
 +      .permission     = nsfs_export_permission,
 +};
 +
  static int nsfs_init_fs_context(struct fs_context *fc)
  {
        struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
diff --cc fs/open.c
index 4890b13461c7bd7df239412c569652e0bd560898,f4bdf76935303635e5d7e7816f91e7f94b7806c5..3d64372ecc675e4795eb0a0deda10f8f67b95640
+++ b/fs/open.c
@@@ -1071,9 -1071,7 +1071,9 @@@ EXPORT_SYMBOL(finish_open)
   */
  int finish_no_open(struct file *file, struct dentry *dentry)
  {
-       file->f_path.dentry = dentry;
 +      if (IS_ERR(dentry))
 +              return PTR_ERR(dentry);
+       file->__f_path.dentry = dentry;
        return 0;
  }
  EXPORT_SYMBOL(finish_no_open);
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc fs/pidfs.c
Simple merge
Simple merge
Simple merge
Simple merge
index a7800ef04e7619cb39974ce5920677d5ed026381,75c0b665fbd41544cec742cad2372abd5f73ce9a..fed86221c69c4bdb6fbd30d985e0af03e20f7b3e
@@@ -57,17 -57,13 +57,17 @@@ struct dentry *lookup_one_qstr_excl(con
                                    struct dentry *base,
                                    unsigned int flags);
  extern int kern_path(const char *, unsigned, struct path *);
 +struct dentry *kern_path_parent(const char *name, struct path *parent);
  
 -extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
 -extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
 -extern void done_path_create(const struct path *, struct dentry *);
 -extern struct dentry *kern_path_locked(const char *, struct path *);
 -extern struct dentry *kern_path_locked_negative(const char *, struct path *);
 -extern struct dentry *user_path_locked_at(int , const char __user *, struct path *);
 +extern struct dentry *start_creating_path(int, const char *, struct path *, unsigned int);
 +extern struct dentry *start_creating_user_path(int, const char __user *, struct path *, unsigned int);
- extern void end_creating_path(struct path *, struct dentry *);
++extern void end_creating_path(const struct path *, struct dentry *);
 +extern struct dentry *start_removing_path(const char *, struct path *);
 +extern struct dentry *start_removing_user_path_at(int , const char __user *, struct path *);
- static inline void end_removing_path(struct path *path , struct dentry *dentry)
++static inline void end_removing_path(const struct path *path , struct dentry *dentry)
 +{
 +      end_creating_path(path, dentry);
 +}
  int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
                           struct path *parent, struct qstr *last, int *type,
                           const struct path *root);
Simple merge