Commit 223b8452 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fs.acl.rework.prep.v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping

Pull vfs acl updates from Christian Brauner:
 "These are general fixes and preparatory changes related to the ongoing
  posix acl rework. The actual rework where we build a type safe posix
  acl api wasn't ready for this merge window but we're hopeful for the
  next merge window.

  General fixes:

   - Some filesystems like 9p and cifs have to implement custom posix
     acl handlers because they require access to the dentry in order to
     set and get posix acls while the set and get inode operations
     currently don't. But the ntfs3 filesystem has no such requirement
     and thus implemented custom posix acl xattr handlers when it really
     didn't have to. So this pr contains patch that just implements set
     and get inode operations for ntfs3 and switches it to rely on the
     generic posix acl xattr handlers. (We would've appreciated reviews
     from the ntfs3 maintainers but we didn't get any. But hey, if we
     really broke it we'll fix it. But fstests for ntfs3 said it's
     fine.)

   - The posix_acl_fix_xattr_common() helper has been adapted so it can
     be used by a few more callers and avoiding open-coding the same
     checks over and over.

  Other than the two general fixes this series introduces a new helper
  vfs_set_acl_prepare(). The reason for this helper is so that we can
  mitigate one of the source that change {g,u}id values directly in the
  uapi struct. With the vfs_set_acl_prepare() helper we can move the
  idmapped mount fixup into the generic posix acl set handler.

  The advantage of this is that it allows us to remove the
  posix_acl_setxattr_idmapped_mnt() helper which so far we had to call
  in vfs_setxattr() to account for idmapped mounts. While semantically
  correct the problem with this approach was that we had to keep the
  value parameter of the generic vfs_setxattr() call as non-const. This
  is rectified in this series.

  Ultimately, we will get rid of all the extreme kludges and type
  unsafety once we have merged the posix api - hopefully during the next
  merge window - built solely around get and set inode operations. Which
  incidentally will also improve handling of posix acls in security and
  especially in integrity modesl. While this will come with temporarily
  having two inode operation for posix acls that is nothing compared to
  the problems we have right now and so well worth it. We'll end up with
  something that we can actually reason about instead of needing to
  write novels to explain what's going on"

* tag 'fs.acl.rework.prep.v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping:
  xattr: always us is_posix_acl_xattr() helper
  acl: fix the comments of posix_acl_xattr_set
  xattr: constify value argument in vfs_setxattr()
  ovl: use vfs_set_acl_prepare()
  acl: move idmapping handling into posix_acl_xattr_set()
  acl: add vfs_set_acl_prepare()
  acl: return EOPNOTSUPP in posix_acl_fix_xattr_common()
  ntfs3: rework xattr handlers and switch to POSIX ACL VFS helpers
parents da380aef 38e31639
...@@ -1927,8 +1927,6 @@ const struct inode_operations ntfs_link_inode_operations = { ...@@ -1927,8 +1927,6 @@ const struct inode_operations ntfs_link_inode_operations = {
.setattr = ntfs3_setattr, .setattr = ntfs3_setattr,
.listxattr = ntfs_listxattr, .listxattr = ntfs_listxattr,
.permission = ntfs_permission, .permission = ntfs_permission,
.get_acl = ntfs_get_acl,
.set_acl = ntfs_set_acl,
}; };
const struct address_space_operations ntfs_aops = { const struct address_space_operations ntfs_aops = {
......
...@@ -625,67 +625,6 @@ int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -625,67 +625,6 @@ int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
return ntfs_set_acl_ex(mnt_userns, inode, acl, type, false); return ntfs_set_acl_ex(mnt_userns, inode, acl, type, false);
} }
static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
struct inode *inode, int type, void *buffer,
size_t size)
{
struct posix_acl *acl;
int err;
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
return -EOPNOTSUPP;
}
acl = ntfs_get_acl(inode, type, false);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (!acl)
return -ENODATA;
err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
posix_acl_release(acl);
return err;
}
static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
struct inode *inode, int type, const void *value,
size_t size)
{
struct posix_acl *acl;
int err;
if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
return -EOPNOTSUPP;
}
if (!inode_owner_or_capable(mnt_userns, inode))
return -EPERM;
if (!value) {
acl = NULL;
} else {
acl = posix_acl_from_xattr(&init_user_ns, value, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl) {
err = posix_acl_valid(&init_user_ns, acl);
if (err)
goto release_and_out;
}
}
err = ntfs_set_acl(mnt_userns, inode, acl, type);
release_and_out:
posix_acl_release(acl);
return err;
}
/* /*
* ntfs_init_acl - Initialize the ACLs of a new inode. * ntfs_init_acl - Initialize the ACLs of a new inode.
* *
...@@ -852,23 +791,6 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de, ...@@ -852,23 +791,6 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
goto out; goto out;
} }
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
(name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
/* TODO: init_user_ns? */
err = ntfs_xattr_get_acl(
&init_user_ns, inode,
name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
? ACL_TYPE_ACCESS
: ACL_TYPE_DEFAULT,
buffer, size);
goto out;
}
#endif
/* Deal with NTFS extended attribute. */ /* Deal with NTFS extended attribute. */
err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL); err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);
...@@ -981,22 +903,6 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler, ...@@ -981,22 +903,6 @@ static noinline int ntfs_setxattr(const struct xattr_handler *handler,
goto out; goto out;
} }
#ifdef CONFIG_NTFS3_FS_POSIX_ACL
if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
(name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
!memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
err = ntfs_xattr_set_acl(
mnt_userns, inode,
name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
? ACL_TYPE_ACCESS
: ACL_TYPE_DEFAULT,
value, size);
goto out;
}
#endif
/* Deal with NTFS extended attribute. */ /* Deal with NTFS extended attribute. */
err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0); err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
...@@ -1086,7 +992,7 @@ static bool ntfs_xattr_user_list(struct dentry *dentry) ...@@ -1086,7 +992,7 @@ static bool ntfs_xattr_user_list(struct dentry *dentry)
} }
// clang-format off // clang-format off
static const struct xattr_handler ntfs_xattr_handler = { static const struct xattr_handler ntfs_other_xattr_handler = {
.prefix = "", .prefix = "",
.get = ntfs_getxattr, .get = ntfs_getxattr,
.set = ntfs_setxattr, .set = ntfs_setxattr,
...@@ -1094,7 +1000,11 @@ static const struct xattr_handler ntfs_xattr_handler = { ...@@ -1094,7 +1000,11 @@ static const struct xattr_handler ntfs_xattr_handler = {
}; };
const struct xattr_handler *ntfs_xattr_handlers[] = { const struct xattr_handler *ntfs_xattr_handlers[] = {
&ntfs_xattr_handler, #ifdef CONFIG_NTFS3_FS_POSIX_ACL
&posix_acl_access_xattr_handler,
&posix_acl_default_xattr_handler,
#endif
&ntfs_other_xattr_handler,
NULL, NULL,
}; };
// clang-format on // clang-format on
...@@ -250,7 +250,7 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry, ...@@ -250,7 +250,7 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
size_t size, int flags) size_t size, int flags)
{ {
int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name, int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name,
(void *)value, size, flags); value, size, flags);
pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n", pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n",
dentry, name, min((int)size, 48), value, size, flags, err); dentry, name, min((int)size, 48), value, size, flags, err);
......
...@@ -1022,7 +1022,20 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler, ...@@ -1022,7 +1022,20 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
/* Check that everything is OK before copy-up */ /* Check that everything is OK before copy-up */
if (value) { if (value) {
acl = posix_acl_from_xattr(&init_user_ns, value, size); /* 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)) if (IS_ERR(acl))
return PTR_ERR(acl); return PTR_ERR(acl);
} }
......
This diff is collapsed.
...@@ -290,7 +290,7 @@ static inline bool is_posix_acl_xattr(const char *name) ...@@ -290,7 +290,7 @@ static inline bool is_posix_acl_xattr(const char *name)
int int
vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry, vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *name, void *value, size_t size, int flags) const char *name, const void *value, size_t size, int flags)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
struct inode *delegated_inode = NULL; struct inode *delegated_inode = NULL;
...@@ -298,16 +298,12 @@ vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry, ...@@ -298,16 +298,12 @@ vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
int error; int error;
if (size && strcmp(name, XATTR_NAME_CAPS) == 0) { if (size && strcmp(name, XATTR_NAME_CAPS) == 0) {
error = cap_convert_nscap(mnt_userns, dentry, error = cap_convert_nscap(mnt_userns, dentry, &value, size);
(const void **)&value, size);
if (error < 0) if (error < 0)
return error; return error;
size = error; size = error;
} }
if (size && is_posix_acl_xattr(name))
posix_acl_setxattr_idmapped_mnt(mnt_userns, inode, value, size);
retry_deleg: retry_deleg:
inode_lock(inode); inode_lock(inode);
error = __vfs_setxattr_locked(mnt_userns, dentry, name, value, size, error = __vfs_setxattr_locked(mnt_userns, dentry, name, value, size,
...@@ -587,9 +583,7 @@ int setxattr_copy(const char __user *name, struct xattr_ctx *ctx) ...@@ -587,9 +583,7 @@ int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
static void setxattr_convert(struct user_namespace *mnt_userns, static void setxattr_convert(struct user_namespace *mnt_userns,
struct dentry *d, struct xattr_ctx *ctx) struct dentry *d, struct xattr_ctx *ctx)
{ {
if (ctx->size && if (ctx->size && is_posix_acl_xattr(ctx->kname->name))
((strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)))
posix_acl_fix_xattr_from_user(ctx->kvalue, ctx->size); posix_acl_fix_xattr_from_user(ctx->kvalue, ctx->size);
} }
...@@ -705,8 +699,7 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d, ...@@ -705,8 +699,7 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
error = vfs_getxattr(mnt_userns, d, kname, ctx->kvalue, ctx->size); error = vfs_getxattr(mnt_userns, d, kname, ctx->kvalue, ctx->size);
if (error > 0) { if (error > 0) {
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || if (is_posix_acl_xattr(kname))
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_to_user(ctx->kvalue, error); posix_acl_fix_xattr_to_user(ctx->kvalue, error);
if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error)) if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
error = -EFAULT; error = -EFAULT;
......
...@@ -38,9 +38,6 @@ void posix_acl_fix_xattr_to_user(void *value, size_t size); ...@@ -38,9 +38,6 @@ void posix_acl_fix_xattr_to_user(void *value, size_t size);
void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns, void posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode, const struct inode *inode,
void *value, size_t size); void *value, size_t size);
void posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode,
void *value, size_t size);
#else #else
static inline void posix_acl_fix_xattr_from_user(void *value, size_t size) static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
{ {
...@@ -54,18 +51,15 @@ posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns, ...@@ -54,18 +51,15 @@ posix_acl_getxattr_idmapped_mnt(struct user_namespace *mnt_userns,
size_t size) size_t size)
{ {
} }
static inline void
posix_acl_setxattr_idmapped_mnt(struct user_namespace *mnt_userns,
const struct inode *inode, void *value,
size_t size)
{
}
#endif #endif
struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns, struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns,
const void *value, size_t size); const void *value, size_t size);
int posix_acl_to_xattr(struct user_namespace *user_ns, int posix_acl_to_xattr(struct user_namespace *user_ns,
const struct posix_acl *acl, void *buffer, size_t size); const struct posix_acl *acl, void *buffer, size_t size);
struct posix_acl *vfs_set_acl_prepare(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns,
const void *value, size_t size);
extern const struct xattr_handler posix_acl_access_xattr_handler; extern const struct xattr_handler posix_acl_access_xattr_handler;
extern const struct xattr_handler posix_acl_default_xattr_handler; extern const struct xattr_handler posix_acl_default_xattr_handler;
......
...@@ -61,7 +61,7 @@ int __vfs_setxattr_locked(struct user_namespace *, struct dentry *, ...@@ -61,7 +61,7 @@ int __vfs_setxattr_locked(struct user_namespace *, struct dentry *,
const char *, const void *, size_t, int, const char *, const void *, size_t, int,
struct inode **); struct inode **);
int vfs_setxattr(struct user_namespace *, struct dentry *, const char *, int vfs_setxattr(struct user_namespace *, struct dentry *, const char *,
void *, size_t, int); const void *, size_t, int);
int __vfs_removexattr(struct user_namespace *, struct dentry *, const char *); int __vfs_removexattr(struct user_namespace *, struct dentry *, const char *);
int __vfs_removexattr_locked(struct user_namespace *, struct dentry *, int __vfs_removexattr_locked(struct user_namespace *, struct dentry *,
const char *, struct inode **); const char *, struct inode **);
......
...@@ -457,10 +457,21 @@ static int evm_xattr_acl_change(struct user_namespace *mnt_userns, ...@@ -457,10 +457,21 @@ static int evm_xattr_acl_change(struct user_namespace *mnt_userns,
int rc; int rc;
/* /*
* user_ns is not relevant here, ACL_USER/ACL_GROUP don't have impact * An earlier comment here mentioned that the idmappings for
* on the inode mode (see posix_acl_equiv_mode()). * ACL_{GROUP,USER} don't matter since EVM is only interested in the
* mode stored as part of POSIX ACLs. Nonetheless, if it must translate
* from the uapi POSIX ACL representation to the VFS internal POSIX ACL
* representation it should do so correctly. There's no guarantee that
* we won't change POSIX ACLs in a way that ACL_{GROUP,USER} matters
* for the mode at some point and it's difficult to keep track of all
* the LSM and integrity modules and what they do to POSIX ACLs.
*
* Frankly, EVM shouldn't try to interpret the uapi struct for POSIX
* ACLs it received. It requires knowledge that only the VFS is
* guaranteed to have.
*/ */
acl = posix_acl_from_xattr(&init_user_ns, xattr_value, xattr_value_len); acl = vfs_set_acl_prepare(mnt_userns, i_user_ns(inode),
xattr_value, xattr_value_len);
if (IS_ERR_OR_NULL(acl)) if (IS_ERR_OR_NULL(acl))
return 1; return 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment