]> Git Repo - J-linux.git/commitdiff
Merge tag 'fs.xattr.simple.noaudit.v6.2' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <[email protected]>
Tue, 13 Dec 2022 04:29:45 +0000 (20:29 -0800)
committerLinus Torvalds <[email protected]>
Tue, 13 Dec 2022 04:29:45 +0000 (20:29 -0800)
Pull xattr audit fix from Seth Forshee:
 "This is a single patch to remove auditing of the capability check in
  simple_xattr_list().

  This check is done to check whether trusted xattrs should be included
  by listxattr(2). SELinux will normally log a denial when capable() is
  called and the task's SELinux context doesn't have the corresponding
  capability permission allowed, which can end up spamming the log.

  Since a failed check here cannot be used to infer malicious intent,
  auditing is of no real value, and it makes sense to stop auditing the
  capability check"

* tag 'fs.xattr.simple.noaudit.v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping:
  fs: don't audit the capability check in simple_xattr_list()

1  2 
fs/xattr.c

diff --combined fs/xattr.c
index 3641a0ce53803fa40f44739de904b3473aee7e3a,427b8cea1f968a29257afc7060bbe6c6f1b0bf54..86668d2ce268b2209378505b0ee981bee2352440
@@@ -80,31 -80,6 +80,31 @@@ xattr_resolve_name(struct inode *inode
        return ERR_PTR(-EOPNOTSUPP);
  }
  
 +/**
 + * may_write_xattr - check whether inode allows writing xattr
 + * @mnt_userns:       User namespace of the mount the inode was found from
 + * @inode: the inode on which to set an xattr
 + *
 + * Check whether the inode allows writing xattrs. Specifically, we can never
 + * set or remove an extended attribute on a read-only filesystem  or on an
 + * immutable / append-only inode.
 + *
 + * We also need to ensure that the inode has a mapping in the mount to
 + * not risk writing back invalid i_{g,u}id values.
 + *
 + * Return: On success zero is returned. On error a negative errno is returned.
 + */
 +int may_write_xattr(struct user_namespace *mnt_userns, struct inode *inode)
 +{
 +      if (IS_IMMUTABLE(inode))
 +              return -EPERM;
 +      if (IS_APPEND(inode))
 +              return -EPERM;
 +      if (HAS_UNMAPPED_ID(mnt_userns, inode))
 +              return -EPERM;
 +      return 0;
 +}
 +
  /*
   * Check permissions for extended attribute access.  This is a bit complicated
   * because different namespaces have very different rules.
@@@ -113,12 -88,20 +113,12 @@@ static in
  xattr_permission(struct user_namespace *mnt_userns, struct inode *inode,
                 const char *name, int mask)
  {
 -      /*
 -       * We can never set or remove an extended attribute on a read-only
 -       * filesystem  or on an immutable / append-only inode.
 -       */
        if (mask & MAY_WRITE) {
 -              if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 -                      return -EPERM;
 -              /*
 -               * Updating an xattr will likely cause i_uid and i_gid
 -               * to be writen back improperly if their true value is
 -               * unknown to the vfs.
 -               */
 -              if (HAS_UNMAPPED_ID(mnt_userns, inode))
 -                      return -EPERM;
 +              int ret;
 +
 +              ret = may_write_xattr(mnt_userns, inode);
 +              if (ret)
 +                      return ret;
        }
  
        /*
@@@ -189,9 -172,6 +189,9 @@@ __vfs_setxattr(struct user_namespace *m
  {
        const struct xattr_handler *handler;
  
 +      if (is_posix_acl_xattr(name))
 +              return -EOPNOTSUPP;
 +
        handler = xattr_resolve_name(inode, &name);
        if (IS_ERR(handler))
                return PTR_ERR(handler);
@@@ -302,6 -282,12 +302,6 @@@ out
  }
  EXPORT_SYMBOL_GPL(__vfs_setxattr_locked);
  
 -static inline bool is_posix_acl_xattr(const char *name)
 -{
 -      return (strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
 -             (strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0);
 -}
 -
  int
  vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
             const char *name, const void *value, size_t size, int flags)
@@@ -413,9 -399,6 +413,9 @@@ __vfs_getxattr(struct dentry *dentry, s
  {
        const struct xattr_handler *handler;
  
 +      if (is_posix_acl_xattr(name))
 +              return -EOPNOTSUPP;
 +
        handler = xattr_resolve_name(inode, &name);
        if (IS_ERR(handler))
                return PTR_ERR(handler);
@@@ -454,7 -437,10 +454,7 @@@ vfs_getxattr(struct user_namespace *mnt
                return ret;
        }
  nolsm:
 -      error = __vfs_getxattr(dentry, inode, name, value, size);
 -      if (error > 0 && is_posix_acl_xattr(name))
 -              posix_acl_getxattr_idmapped_mnt(mnt_userns, inode, value, size);
 -      return error;
 +      return __vfs_getxattr(dentry, inode, name, value, size);
  }
  EXPORT_SYMBOL_GPL(vfs_getxattr);
  
@@@ -485,9 -471,6 +485,9 @@@ __vfs_removexattr(struct user_namespac
        struct inode *inode = d_inode(dentry);
        const struct xattr_handler *handler;
  
 +      if (is_posix_acl_xattr(name))
 +              return -EOPNOTSUPP;
 +
        handler = xattr_resolve_name(inode, &name);
        if (IS_ERR(handler))
                return PTR_ERR(handler);
@@@ -597,19 -580,23 +597,19 @@@ int setxattr_copy(const char __user *na
        return error;
  }
  
 -static void setxattr_convert(struct user_namespace *mnt_userns,
 -                           struct dentry *d, struct xattr_ctx *ctx)
 -{
 -      if (ctx->size && is_posix_acl_xattr(ctx->kname->name))
 -              posix_acl_fix_xattr_from_user(ctx->kvalue, ctx->size);
 -}
 -
 -int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
 +int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
                struct xattr_ctx *ctx)
  {
 -      setxattr_convert(mnt_userns, dentry, ctx);
 -      return vfs_setxattr(mnt_userns, dentry, ctx->kname->name,
 +      if (is_posix_acl_xattr(ctx->kname->name))
 +              return do_set_acl(idmap, dentry, ctx->kname->name,
 +                                ctx->kvalue, ctx->size);
 +
 +      return vfs_setxattr(mnt_idmap_owner(idmap), dentry, ctx->kname->name,
                        ctx->kvalue, ctx->size, ctx->flags);
  }
  
  static long
 -setxattr(struct user_namespace *mnt_userns, struct dentry *d,
 +setxattr(struct mnt_idmap *idmap, struct dentry *d,
        const char __user *name, const void __user *value, size_t size,
        int flags)
  {
        if (error)
                return error;
  
 -      error = do_setxattr(mnt_userns, d, &ctx);
 +      error = do_setxattr(idmap, d, &ctx);
  
        kvfree(ctx.kvalue);
        return error;
@@@ -646,7 -633,7 +646,7 @@@ retry
                return error;
        error = mnt_want_write(path.mnt);
        if (!error) {
 -              error = setxattr(mnt_user_ns(path.mnt), path.dentry, name,
 +              error = setxattr(mnt_idmap(path.mnt), path.dentry, name,
                                 value, size, flags);
                mnt_drop_write(path.mnt);
        }
@@@ -683,7 -670,7 +683,7 @@@ SYSCALL_DEFINE5(fsetxattr, int, fd, con
        audit_file(f.file);
        error = mnt_want_write_file(f.file);
        if (!error) {
 -              error = setxattr(file_mnt_user_ns(f.file),
 +              error = setxattr(file_mnt_idmap(f.file),
                                 f.file->f_path.dentry, name,
                                 value, size, flags);
                mnt_drop_write_file(f.file);
   * Extended attribute GET operations
   */
  ssize_t
 -do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
 +do_getxattr(struct mnt_idmap *idmap, struct dentry *d,
        struct xattr_ctx *ctx)
  {
        ssize_t error;
                        return -ENOMEM;
        }
  
 -      error = vfs_getxattr(mnt_userns, d, kname, ctx->kvalue, ctx->size);
 +      if (is_posix_acl_xattr(ctx->kname->name))
 +              error = do_get_acl(idmap, d, kname, ctx->kvalue, ctx->size);
 +      else
 +              error = vfs_getxattr(mnt_idmap_owner(idmap), d, kname,
 +                                   ctx->kvalue, ctx->size);
        if (error > 0) {
 -              if (is_posix_acl_xattr(kname))
 -                      posix_acl_fix_xattr_to_user(ctx->kvalue, error);
                if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
                        error = -EFAULT;
        } else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {
  }
  
  static ssize_t
 -getxattr(struct user_namespace *mnt_userns, struct dentry *d,
 +getxattr(struct mnt_idmap *idmap, struct dentry *d,
         const char __user *name, void __user *value, size_t size)
  {
        ssize_t error;
        if (error < 0)
                return error;
  
 -      error =  do_getxattr(mnt_userns, d, &ctx);
 +      error =  do_getxattr(idmap, d, &ctx);
  
        kvfree(ctx.kvalue);
        return error;
@@@ -763,7 -748,7 +763,7 @@@ retry
        error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
 -      error = getxattr(mnt_user_ns(path.mnt), path.dentry, name, value, size);
 +      error = getxattr(mnt_idmap(path.mnt), path.dentry, name, value, size);
        path_put(&path);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
@@@ -793,7 -778,7 +793,7 @@@ SYSCALL_DEFINE4(fgetxattr, int, fd, con
        if (!f.file)
                return error;
        audit_file(f.file);
 -      error = getxattr(file_mnt_user_ns(f.file), f.file->f_path.dentry,
 +      error = getxattr(file_mnt_idmap(f.file), f.file->f_path.dentry,
                         name, value, size);
        fdput(f);
        return error;
@@@ -878,7 -863,7 +878,7 @@@ SYSCALL_DEFINE3(flistxattr, int, fd, ch
   * Extended attribute REMOVE operations
   */
  static long
 -removexattr(struct user_namespace *mnt_userns, struct dentry *d,
 +removexattr(struct mnt_idmap *idmap, struct dentry *d,
            const char __user *name)
  {
        int error;
        if (error < 0)
                return error;
  
 -      return vfs_removexattr(mnt_userns, d, kname);
 +      if (is_posix_acl_xattr(kname))
 +              return vfs_remove_acl(mnt_idmap_owner(idmap), d, kname);
 +
 +      return vfs_removexattr(mnt_idmap_owner(idmap), d, kname);
  }
  
  static int path_removexattr(const char __user *pathname,
@@@ -907,7 -889,7 +907,7 @@@ retry
                return error;
        error = mnt_want_write(path.mnt);
        if (!error) {
 -              error = removexattr(mnt_user_ns(path.mnt), path.dentry, name);
 +              error = removexattr(mnt_idmap(path.mnt), path.dentry, name);
                mnt_drop_write(path.mnt);
        }
        path_put(&path);
@@@ -940,7 -922,7 +940,7 @@@ SYSCALL_DEFINE2(fremovexattr, int, fd, 
        audit_file(f.file);
        error = mnt_want_write_file(f.file);
        if (!error) {
 -              error = removexattr(file_mnt_user_ns(f.file),
 +              error = removexattr(file_mnt_idmap(f.file),
                                    f.file->f_path.dentry, name);
                mnt_drop_write_file(f.file);
        }
@@@ -1158,7 -1140,7 +1158,7 @@@ static int xattr_list_one(char **buffer
  ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
                          char *buffer, size_t size)
  {
-       bool trusted = capable(CAP_SYS_ADMIN);
+       bool trusted = ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
        struct simple_xattr *xattr;
        ssize_t remaining_size = size;
        int err = 0;
This page took 0.064597 seconds and 4 git commands to generate.