Commit 318e6685 authored by Christian Brauner's avatar Christian Brauner Committed by Christian Brauner (Microsoft)

xattr: use posix acl api

In previous patches we built a new posix api solely around get and set
inode operations. Now that we have all the pieces in place we can switch
the system calls and the vfs over to only rely on this api when
interacting with posix acls. This finally removes all type unsafety and
type conversion issues explained in detail in [1] that we aim to get rid
of.

With the new posix acl api we immediately translate into an appropriate
kernel internal struct posix_acl format both when getting and setting
posix acls. This is a stark contrast to before were we hacked unsafe raw
values into the uapi struct that was stored in a void pointer relying
and having filesystems and security modules hack around in the uapi
struct as well.

Link: https://lore.kernel.org/all/20220801145520.1532837-1-brauner@kernel.org [1]
Signed-off-by: default avatarChristian Brauner (Microsoft) <brauner@kernel.org>
parent 31acceb9
...@@ -234,4 +234,24 @@ int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry, ...@@ -234,4 +234,24 @@ int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct xattr_ctx *ctx); struct xattr_ctx *ctx);
int may_write_xattr(struct user_namespace *mnt_userns, struct inode *inode); int may_write_xattr(struct user_namespace *mnt_userns, struct inode *inode);
#ifdef CONFIG_FS_POSIX_ACL
int do_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, const void *kvalue, size_t size);
ssize_t do_get_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, void *kvalue, size_t size);
#else
static inline int do_set_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
const void *kvalue, size_t size)
{
return -EOPNOTSUPP;
}
static inline ssize_t do_get_acl(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *acl_name,
void *kvalue, size_t size)
{
return -EOPNOTSUPP;
}
#endif
ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *pos); ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *pos);
...@@ -1544,3 +1544,40 @@ int vfs_remove_acl(struct user_namespace *mnt_userns, struct dentry *dentry, ...@@ -1544,3 +1544,40 @@ int vfs_remove_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
return error; return error;
} }
EXPORT_SYMBOL_GPL(vfs_remove_acl); EXPORT_SYMBOL_GPL(vfs_remove_acl);
int do_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, const void *kvalue, size_t size)
{
int error;
struct posix_acl *acl = NULL;
if (size) {
/*
* Note that posix_acl_from_xattr() uses GFP_NOFS when it
* probably doesn't need to here.
*/
acl = posix_acl_from_xattr(current_user_ns(), kvalue, size);
if (IS_ERR(acl))
return PTR_ERR(acl);
}
error = vfs_set_acl(mnt_userns, dentry, acl_name, acl);
posix_acl_release(acl);
return error;
}
ssize_t do_get_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
const char *acl_name, void *kvalue, size_t size)
{
ssize_t error;
struct posix_acl *acl;
acl = vfs_get_acl(mnt_userns, dentry, acl_name);
if (IS_ERR(acl))
return PTR_ERR(acl);
error = vfs_posix_acl_to_xattr(mnt_userns, d_inode(dentry),
acl, kvalue, size);
posix_acl_release(acl);
return error;
}
...@@ -189,6 +189,9 @@ __vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry, ...@@ -189,6 +189,9 @@ __vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
{ {
const struct xattr_handler *handler; const struct xattr_handler *handler;
if (is_posix_acl_xattr(name))
return -EOPNOTSUPP;
handler = xattr_resolve_name(inode, &name); handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler)) if (IS_ERR(handler))
return PTR_ERR(handler); return PTR_ERR(handler);
...@@ -410,6 +413,9 @@ __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, ...@@ -410,6 +413,9 @@ __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
{ {
const struct xattr_handler *handler; const struct xattr_handler *handler;
if (is_posix_acl_xattr(name))
return -EOPNOTSUPP;
handler = xattr_resolve_name(inode, &name); handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler)) if (IS_ERR(handler))
return PTR_ERR(handler); return PTR_ERR(handler);
...@@ -482,6 +488,9 @@ __vfs_removexattr(struct user_namespace *mnt_userns, struct dentry *dentry, ...@@ -482,6 +488,9 @@ __vfs_removexattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
const struct xattr_handler *handler; const struct xattr_handler *handler;
if (is_posix_acl_xattr(name))
return -EOPNOTSUPP;
handler = xattr_resolve_name(inode, &name); handler = xattr_resolve_name(inode, &name);
if (IS_ERR(handler)) if (IS_ERR(handler))
return PTR_ERR(handler); return PTR_ERR(handler);
...@@ -591,17 +600,13 @@ int setxattr_copy(const char __user *name, struct xattr_ctx *ctx) ...@@ -591,17 +600,13 @@ int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
return error; 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 user_namespace *mnt_userns, struct dentry *dentry,
struct xattr_ctx *ctx) struct xattr_ctx *ctx)
{ {
setxattr_convert(mnt_userns, dentry, ctx); if (is_posix_acl_xattr(ctx->kname->name))
return do_set_acl(mnt_userns, dentry, ctx->kname->name,
ctx->kvalue, ctx->size);
return vfs_setxattr(mnt_userns, dentry, ctx->kname->name, return vfs_setxattr(mnt_userns, dentry, ctx->kname->name,
ctx->kvalue, ctx->size, ctx->flags); ctx->kvalue, ctx->size, ctx->flags);
} }
...@@ -708,10 +713,11 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d, ...@@ -708,10 +713,11 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
return -ENOMEM; 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(mnt_userns, d, kname, ctx->kvalue, ctx->size);
else
error = vfs_getxattr(mnt_userns, d, kname, ctx->kvalue, ctx->size);
if (error > 0) { 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)) if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
error = -EFAULT; error = -EFAULT;
} else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) { } else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {
...@@ -886,6 +892,9 @@ removexattr(struct user_namespace *mnt_userns, struct dentry *d, ...@@ -886,6 +892,9 @@ removexattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error < 0) if (error < 0)
return error; return error;
if (is_posix_acl_xattr(kname))
return vfs_remove_acl(mnt_userns, d, kname);
return vfs_removexattr(mnt_userns, d, kname); return vfs_removexattr(mnt_userns, d, kname);
} }
......
...@@ -33,6 +33,8 @@ posix_acl_xattr_count(size_t size) ...@@ -33,6 +33,8 @@ posix_acl_xattr_count(size_t size)
} }
#ifdef CONFIG_FS_POSIX_ACL #ifdef CONFIG_FS_POSIX_ACL
struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns,
const void *value, size_t size);
void posix_acl_fix_xattr_from_user(void *value, size_t size); void posix_acl_fix_xattr_from_user(void *value, size_t size);
void posix_acl_fix_xattr_to_user(void *value, size_t size); 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,
...@@ -42,6 +44,12 @@ ssize_t vfs_posix_acl_to_xattr(struct user_namespace *mnt_userns, ...@@ -42,6 +44,12 @@ ssize_t vfs_posix_acl_to_xattr(struct user_namespace *mnt_userns,
struct inode *inode, const struct posix_acl *acl, struct inode *inode, const struct posix_acl *acl,
void *buffer, size_t size); void *buffer, size_t size);
#else #else
static inline struct posix_acl *
posix_acl_from_xattr(struct user_namespace *user_ns, const void *value,
size_t size)
{
return ERR_PTR(-EOPNOTSUPP);
}
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)
{ {
} }
...@@ -63,8 +71,6 @@ static inline ssize_t vfs_posix_acl_to_xattr(struct user_namespace *mnt_userns, ...@@ -63,8 +71,6 @@ static inline ssize_t vfs_posix_acl_to_xattr(struct user_namespace *mnt_userns,
} }
#endif #endif
struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns,
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 posix_acl *vfs_set_acl_prepare(struct user_namespace *mnt_userns,
......
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