]> Git Repo - linux.git/commitdiff
Merge tag 'pull-statx' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <[email protected]>
Mon, 18 Nov 2024 22:54:10 +0000 (14:54 -0800)
committerLinus Torvalds <[email protected]>
Mon, 18 Nov 2024 22:54:10 +0000 (14:54 -0800)
Pull statx updates from Al Viro:
 "Sanitize struct filename and lookup flags handling in statx and
  friends"

* tag 'pull-statx' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  libfs: kill empty_dir_getattr()
  fs: Simplify getattr interface function checking AT_GETATTR_NOSEC flag
  fs/stat.c: switch to CLASS(fd_raw)
  kill getname_statx_lookup_flags()
  io_statx_prep(): use getname_uflags()

1  2 
fs/ecryptfs/inode.c
fs/internal.h
fs/libfs.c
fs/stat.c

diff --combined fs/ecryptfs/inode.c
index cbdf82f0183f3d2f21125667efd6864480b7e650,644e973d5a77c8af9a6aac4d6abab4728378dfeb..a9819ddb1ab85c70b6e80ec0efbdbaf3ca29c351
@@@ -21,7 -21,7 +21,7 @@@
  #include <linux/posix_acl.h>
  #include <linux/posix_acl_xattr.h>
  #include <linux/fileattr.h>
 -#include <asm/unaligned.h>
 +#include <linux/unaligned.h>
  #include "ecryptfs_kernel.h"
  
  static int lock_parent(struct dentry *dentry,
@@@ -1008,14 -1008,6 +1008,6 @@@ static int ecryptfs_getattr_link(struc
        return rc;
  }
  
- static int ecryptfs_do_getattr(const struct path *path, struct kstat *stat,
-                              u32 request_mask, unsigned int flags)
- {
-       if (flags & AT_GETATTR_NOSEC)
-               return vfs_getattr_nosec(path, stat, request_mask, flags);
-       return vfs_getattr(path, stat, request_mask, flags);
- }
  static int ecryptfs_getattr(struct mnt_idmap *idmap,
                            const struct path *path, struct kstat *stat,
                            u32 request_mask, unsigned int flags)
        struct kstat lower_stat;
        int rc;
  
-       rc = ecryptfs_do_getattr(ecryptfs_dentry_to_lower_path(dentry),
-                                &lower_stat, request_mask, flags);
+       rc = vfs_getattr_nosec(ecryptfs_dentry_to_lower_path(dentry),
+                              &lower_stat, request_mask, flags);
        if (!rc) {
                fsstack_copy_attr_all(d_inode(dentry),
                                      ecryptfs_inode_to_lower(d_inode(dentry)));
diff --combined fs/internal.h
index 8001efd1f047b54510bba6471865e37840c8f404,8cf42b327e5ed122b1e19e4ba5ecdfbe6ad11581..e7f02ae1e0981bd129a995c02f3b7a5defd7c669
@@@ -246,7 -246,6 +246,6 @@@ int open_namespace(struct ns_common *ns
   * fs/stat.c:
   */
  
- int getname_statx_lookup_flags(int flags);
  int do_statx(int dfd, struct filename *filename, unsigned int flags,
             unsigned int mask, struct statx __user *buffer);
  int do_statx_fd(int fd, unsigned int flags, unsigned int mask,
@@@ -267,7 -266,7 +266,7 @@@ struct xattr_name 
        char name[XATTR_NAME_MAX + 1];
  };
  
 -struct xattr_ctx {
 +struct kernel_xattr_ctx {
        /* Value of attribute */
        union {
                const void __user *cvalue;
        unsigned int flags;
  };
  
 +ssize_t file_getxattr(struct file *file, struct kernel_xattr_ctx *ctx);
 +ssize_t filename_getxattr(int dfd, struct filename *filename,
 +                        unsigned int lookup_flags, struct kernel_xattr_ctx *ctx);
 +int file_setxattr(struct file *file, struct kernel_xattr_ctx *ctx);
 +int filename_setxattr(int dfd, struct filename *filename,
 +                    unsigned int lookup_flags, struct kernel_xattr_ctx *ctx);
 +int setxattr_copy(const char __user *name, struct kernel_xattr_ctx *ctx);
 +int import_xattr_name(struct xattr_name *kname, const char __user *name);
  
 -ssize_t do_getxattr(struct mnt_idmap *idmap,
 -                  struct dentry *d,
 -                  struct xattr_ctx *ctx);
 -
 -int setxattr_copy(const char __user *name, struct xattr_ctx *ctx);
 -int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
 -              struct xattr_ctx *ctx);
  int may_write_xattr(struct mnt_idmap *idmap, struct inode *inode);
  
  #ifdef CONFIG_FS_POSIX_ACL
diff --combined fs/libfs.c
index a168ece5cc61b74114f537f5b7b8a07f2d48b2aa,12f5185f3fa98e14514be469e9f8a56b350cecd5..748ac59231547c29abcbade3fa025e3b00533d8b
@@@ -77,10 -77,6 +77,10 @@@ struct dentry *simple_lookup(struct ino
                return ERR_PTR(-ENAMETOOLONG);
        if (!dentry->d_sb->s_d_op)
                d_set_d_op(dentry, &simple_dentry_operations);
 +
 +      if (IS_ENABLED(CONFIG_UNICODE) && IS_CASEFOLDED(dir))
 +              return NULL;
 +
        d_add(dentry, NULL);
        return NULL;
  }
@@@ -1715,15 -1711,6 +1715,6 @@@ static struct dentry *empty_dir_lookup(
        return ERR_PTR(-ENOENT);
  }
  
- static int empty_dir_getattr(struct mnt_idmap *idmap,
-                            const struct path *path, struct kstat *stat,
-                            u32 request_mask, unsigned int query_flags)
- {
-       struct inode *inode = d_inode(path->dentry);
-       generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
-       return 0;
- }
  static int empty_dir_setattr(struct mnt_idmap *idmap,
                             struct dentry *dentry, struct iattr *attr)
  {
@@@ -1737,9 -1724,7 +1728,7 @@@ static ssize_t empty_dir_listxattr(stru
  
  static const struct inode_operations empty_dir_inode_operations = {
        .lookup         = empty_dir_lookup,
-       .permission     = generic_permission,
        .setattr        = empty_dir_setattr,
-       .getattr        = empty_dir_getattr,
        .listxattr      = empty_dir_listxattr,
  };
  
@@@ -1795,8 -1780,8 +1784,8 @@@ bool is_empty_dir_inode(struct inode *i
   *
   * Return: 0 if names match, 1 if mismatch, or -ERRNO
   */
 -static int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
 -                              const char *str, const struct qstr *name)
 +int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
 +                       const char *str, const struct qstr *name)
  {
        const struct dentry *parent;
        const struct inode *dir;
  
        return utf8_strncasecmp(dentry->d_sb->s_encoding, name, &qstr);
  }
 +EXPORT_SYMBOL(generic_ci_d_compare);
  
  /**
   * generic_ci_d_hash - generic d_hash implementation for casefolding filesystems
   *
   * Return: 0 if hash was successful or unchanged, and -EINVAL on error
   */
 -static int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
 +int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
  {
        const struct inode *dir = READ_ONCE(dentry->d_inode);
        struct super_block *sb = dentry->d_sb;
                return -EINVAL;
        return 0;
  }
 +EXPORT_SYMBOL(generic_ci_d_hash);
  
  static const struct dentry_operations generic_ci_dentry_ops = {
        .d_hash = generic_ci_d_hash,
diff --combined fs/stat.c
index 224fbdaa2d133647708c1655acf20bc81489b812,011d2160b7affab0bdce3659b6f6ab6b13ecce02..0870e969a8a0b80eefb8b737262a69d7bf28feec
+++ b/fs/stat.c
  #include <linux/uaccess.h>
  #include <asm/unistd.h>
  
 +#include <trace/events/timestamp.h>
 +
  #include "internal.h"
  #include "mount.h"
  
 +/**
 + * fill_mg_cmtime - Fill in the mtime and ctime and flag ctime as QUERIED
 + * @stat: where to store the resulting values
 + * @request_mask: STATX_* values requested
 + * @inode: inode from which to grab the c/mtime
 + *
 + * Given @inode, grab the ctime and mtime out if it and store the result
 + * in @stat. When fetching the value, flag it as QUERIED (if not already)
 + * so the next write will record a distinct timestamp.
 + *
 + * NB: The QUERIED flag is tracked in the ctime, but we set it there even
 + * if only the mtime was requested, as that ensures that the next mtime
 + * change will be distinct.
 + */
 +void fill_mg_cmtime(struct kstat *stat, u32 request_mask, struct inode *inode)
 +{
 +      atomic_t *pcn = (atomic_t *)&inode->i_ctime_nsec;
 +
 +      /* If neither time was requested, then don't report them */
 +      if (!(request_mask & (STATX_CTIME|STATX_MTIME))) {
 +              stat->result_mask &= ~(STATX_CTIME|STATX_MTIME);
 +              return;
 +      }
 +
 +      stat->mtime = inode_get_mtime(inode);
 +      stat->ctime.tv_sec = inode->i_ctime_sec;
 +      stat->ctime.tv_nsec = (u32)atomic_read(pcn);
 +      if (!(stat->ctime.tv_nsec & I_CTIME_QUERIED))
 +              stat->ctime.tv_nsec = ((u32)atomic_fetch_or(I_CTIME_QUERIED, pcn));
 +      stat->ctime.tv_nsec &= ~I_CTIME_QUERIED;
 +      trace_fill_mg_cmtime(inode, &stat->ctime, &stat->mtime);
 +}
 +EXPORT_SYMBOL(fill_mg_cmtime);
 +
  /**
   * generic_fillattr - Fill in the basic attributes from the inode struct
   * @idmap:            idmap of the mount the inode was found from
@@@ -94,14 -58,8 +94,14 @@@ void generic_fillattr(struct mnt_idmap 
        stat->rdev = inode->i_rdev;
        stat->size = i_size_read(inode);
        stat->atime = inode_get_atime(inode);
 -      stat->mtime = inode_get_mtime(inode);
 -      stat->ctime = inode_get_ctime(inode);
 +
 +      if (is_mgtime(inode)) {
 +              fill_mg_cmtime(stat, request_mask, inode);
 +      } else {
 +              stat->ctime = inode_get_ctime(inode);
 +              stat->mtime = inode_get_mtime(inode);
 +      }
 +
        stat->blksize = i_blocksize(inode);
        stat->blocks = inode->i_blocks;
  
@@@ -207,7 -165,7 +207,7 @@@ int vfs_getattr_nosec(const struct pat
        if (inode->i_op->getattr)
                return inode->i_op->getattr(idmap, path, stat,
                                            request_mask,
-                                           query_flags | AT_GETATTR_NOSEC);
+                                           query_flags);
  
        generic_fillattr(idmap, request_mask, inode, stat);
        return 0;
@@@ -240,9 -198,6 +240,6 @@@ int vfs_getattr(const struct path *path
  {
        int retval;
  
-       if (WARN_ON_ONCE(query_flags & AT_GETATTR_NOSEC))
-               return -EPERM;
        retval = security_inode_getattr(path);
        if (retval)
                return retval;
@@@ -262,18 -217,13 +259,13 @@@ EXPORT_SYMBOL(vfs_getattr)
   */
  int vfs_fstat(int fd, struct kstat *stat)
  {
-       struct fd f;
-       int error;
-       f = fdget_raw(fd);
-       if (!fd_file(f))
+       CLASS(fd_raw, f)(fd);
+       if (fd_empty(f))
                return -EBADF;
-       error = vfs_getattr(&fd_file(f)->f_path, stat, STATX_BASIC_STATS, 0);
-       fdput(f);
-       return error;
+       return vfs_getattr(&fd_file(f)->f_path, stat, STATX_BASIC_STATS, 0);
  }
  
int getname_statx_lookup_flags(int flags)
static int statx_lookup_flags(int flags)
  {
        int lookup_flags = 0;
  
                lookup_flags |= LOOKUP_FOLLOW;
        if (!(flags & AT_NO_AUTOMOUNT))
                lookup_flags |= LOOKUP_AUTOMOUNT;
-       if (flags & AT_EMPTY_PATH)
-               lookup_flags |= LOOKUP_EMPTY;
  
        return lookup_flags;
  }
@@@ -319,7 -267,7 +309,7 @@@ static int vfs_statx_fd(int fd, int fla
                          u32 request_mask)
  {
        CLASS(fd_raw, f)(fd);
-       if (!fd_file(f))
+       if (fd_empty(f))
                return -EBADF;
        return vfs_statx_path(&fd_file(f)->f_path, flags, stat, request_mask);
  }
@@@ -343,7 -291,7 +333,7 @@@ static int vfs_statx(int dfd, struct fi
              struct kstat *stat, u32 request_mask)
  {
        struct path path;
-       unsigned int lookup_flags = getname_statx_lookup_flags(flags);
+       unsigned int lookup_flags = statx_lookup_flags(flags);
        int error;
  
        if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH |
This page took 0.082479 seconds and 4 git commands to generate.