summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/internal.h20
-rw-r--r--fs/posix_acl.c37
-rw-r--r--fs/xattr.c31
-rw-r--r--include/linux/posix_acl_xattr.h10
4 files changed, 85 insertions, 13 deletions
diff --git a/fs/internal.h b/fs/internal.h
index aa5f240496d9..e377eb7bbe7f 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -234,4 +234,24 @@ int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
struct xattr_ctx *ctx);
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);
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 3a141082b24c..14b87653b797 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -1544,3 +1544,40 @@ out_inode_unlock:
return error;
}
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;
+}
diff --git a/fs/xattr.c b/fs/xattr.c
index 9ed9eea4d1b9..77db5aa26d13 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -189,6 +189,9 @@ __vfs_setxattr(struct user_namespace *mnt_userns, struct dentry *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);
@@ -410,6 +413,9 @@ __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
{
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);
@@ -482,6 +488,9 @@ __vfs_removexattr(struct user_namespace *mnt_userns, struct dentry *dentry,
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);
@@ -591,17 +600,13 @@ int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
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,
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,
ctx->kvalue, ctx->size, ctx->flags);
}
@@ -708,10 +713,11 @@ do_getxattr(struct user_namespace *mnt_userns, struct dentry *d,
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 (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) {
@@ -886,6 +892,9 @@ removexattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error < 0)
return error;
+ if (is_posix_acl_xattr(kname))
+ return vfs_remove_acl(mnt_userns, d, kname);
+
return vfs_removexattr(mnt_userns, d, kname);
}
diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h
index bf30296389d7..c5d5fbc348dc 100644
--- a/include/linux/posix_acl_xattr.h
+++ b/include/linux/posix_acl_xattr.h
@@ -33,6 +33,8 @@ posix_acl_xattr_count(size_t size)
}
#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_to_user(void *value, size_t size);
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,
struct inode *inode, const struct posix_acl *acl,
void *buffer, size_t size);
#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)
{
}
@@ -63,8 +71,6 @@ static inline ssize_t vfs_posix_acl_to_xattr(struct user_namespace *mnt_userns,
}
#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,
const struct posix_acl *acl, void *buffer, size_t size);
struct posix_acl *vfs_set_acl_prepare(struct user_namespace *mnt_userns,