ovl: Move xattr support to new xattrs.c file
This moves the code from super.c and inode.c, and makes ovl_xattr_get/set() static. This is in preparation for doing more work on xattrs support. Signed-off-by: Alexander Larsson <alexl@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
This commit is contained in:
parent
5b02bfc1e7
commit
420a62dde6
@ -6,4 +6,4 @@
|
||||
obj-$(CONFIG_OVERLAY_FS) += overlay.o
|
||||
|
||||
overlay-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \
|
||||
copy_up.o export.o params.o
|
||||
copy_up.o export.o params.o xattrs.o
|
||||
|
@ -339,128 +339,6 @@ static const char *ovl_get_link(struct dentry *dentry,
|
||||
return p;
|
||||
}
|
||||
|
||||
bool ovl_is_private_xattr(struct super_block *sb, const char *name)
|
||||
{
|
||||
struct ovl_fs *ofs = OVL_FS(sb);
|
||||
|
||||
if (ofs->config.userxattr)
|
||||
return strncmp(name, OVL_XATTR_USER_PREFIX,
|
||||
sizeof(OVL_XATTR_USER_PREFIX) - 1) == 0;
|
||||
else
|
||||
return strncmp(name, OVL_XATTR_TRUSTED_PREFIX,
|
||||
sizeof(OVL_XATTR_TRUSTED_PREFIX) - 1) == 0;
|
||||
}
|
||||
|
||||
int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
int err;
|
||||
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
|
||||
struct dentry *upperdentry = ovl_i_dentry_upper(inode);
|
||||
struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
|
||||
struct path realpath;
|
||||
const struct cred *old_cred;
|
||||
|
||||
if (!value && !upperdentry) {
|
||||
ovl_path_lower(dentry, &realpath);
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
|
||||
revert_creds(old_cred);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!upperdentry) {
|
||||
err = ovl_copy_up(dentry);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
realdentry = ovl_dentry_upper(dentry);
|
||||
}
|
||||
|
||||
err = ovl_want_write(dentry);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
if (value) {
|
||||
err = ovl_do_setxattr(ofs, realdentry, name, value, size,
|
||||
flags);
|
||||
} else {
|
||||
WARN_ON(flags != XATTR_REPLACE);
|
||||
err = ovl_do_removexattr(ofs, realdentry, name);
|
||||
}
|
||||
revert_creds(old_cred);
|
||||
ovl_drop_write(dentry);
|
||||
|
||||
/* copy c/mtime */
|
||||
ovl_copyattr(inode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
ssize_t res;
|
||||
const struct cred *old_cred;
|
||||
struct path realpath;
|
||||
|
||||
ovl_i_path_real(inode, &realpath);
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
res = vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size);
|
||||
revert_creds(old_cred);
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool ovl_can_list(struct super_block *sb, const char *s)
|
||||
{
|
||||
/* Never list private (.overlay) */
|
||||
if (ovl_is_private_xattr(sb, s))
|
||||
return false;
|
||||
|
||||
/* List all non-trusted xattrs */
|
||||
if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
|
||||
return true;
|
||||
|
||||
/* list other trusted for superuser only */
|
||||
return ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
|
||||
}
|
||||
|
||||
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
|
||||
{
|
||||
struct dentry *realdentry = ovl_dentry_real(dentry);
|
||||
ssize_t res;
|
||||
size_t len;
|
||||
char *s;
|
||||
const struct cred *old_cred;
|
||||
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
res = vfs_listxattr(realdentry, list, size);
|
||||
revert_creds(old_cred);
|
||||
if (res <= 0 || size == 0)
|
||||
return res;
|
||||
|
||||
/* filter out private xattrs */
|
||||
for (s = list, len = res; len;) {
|
||||
size_t slen = strnlen(s, len) + 1;
|
||||
|
||||
/* underlying fs providing us with an broken xattr list? */
|
||||
if (WARN_ON(slen > len))
|
||||
return -EIO;
|
||||
|
||||
len -= slen;
|
||||
if (!ovl_can_list(dentry->d_sb, s)) {
|
||||
res -= slen;
|
||||
memmove(s, s + slen, len);
|
||||
} else {
|
||||
s += slen;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
/*
|
||||
* Apply the idmapping of the layer to POSIX ACLs. The caller must pass a clone
|
||||
|
@ -699,17 +699,8 @@ int ovl_set_nlink_lower(struct dentry *dentry);
|
||||
unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry,
|
||||
struct dentry *upperdentry,
|
||||
unsigned int fallback);
|
||||
int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int flags);
|
||||
int ovl_permission(struct mnt_idmap *idmap, struct inode *inode,
|
||||
int mask);
|
||||
int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
void *value, size_t size);
|
||||
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
|
||||
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
struct posix_acl *do_ovl_get_acl(struct mnt_idmap *idmap,
|
||||
@ -846,3 +837,12 @@ static inline bool ovl_force_readonly(struct ovl_fs *ofs)
|
||||
{
|
||||
return (!ovl_upper_mnt(ofs) || !ofs->workdir);
|
||||
}
|
||||
|
||||
/* xattr.c */
|
||||
|
||||
const struct xattr_handler * const *ovl_xattr_handlers(struct ovl_fs *ofs);
|
||||
int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr);
|
||||
int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int flags);
|
||||
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
|
||||
|
@ -445,68 +445,6 @@ static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir)
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int ovl_own_xattr_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ovl_own_xattr_set(const struct xattr_handler *handler,
|
||||
struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ovl_other_xattr_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ovl_xattr_get(dentry, inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int ovl_other_xattr_set(const struct xattr_handler *handler,
|
||||
struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
return ovl_xattr_set(dentry, inode, name, value, size, flags);
|
||||
}
|
||||
|
||||
static const struct xattr_handler ovl_own_trusted_xattr_handler = {
|
||||
.prefix = OVL_XATTR_TRUSTED_PREFIX,
|
||||
.get = ovl_own_xattr_get,
|
||||
.set = ovl_own_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler ovl_own_user_xattr_handler = {
|
||||
.prefix = OVL_XATTR_USER_PREFIX,
|
||||
.get = ovl_own_xattr_get,
|
||||
.set = ovl_own_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler ovl_other_xattr_handler = {
|
||||
.prefix = "", /* catch all */
|
||||
.get = ovl_other_xattr_get,
|
||||
.set = ovl_other_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler * const ovl_trusted_xattr_handlers[] = {
|
||||
&ovl_own_trusted_xattr_handler,
|
||||
&ovl_other_xattr_handler,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct xattr_handler * const ovl_user_xattr_handlers[] = {
|
||||
&ovl_own_user_xattr_handler,
|
||||
&ovl_other_xattr_handler,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ovl_setup_trap(struct super_block *sb, struct dentry *dir,
|
||||
struct inode **ptrap, const char *name)
|
||||
{
|
||||
@ -1501,8 +1439,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
|
||||
|
||||
sb->s_magic = OVERLAYFS_SUPER_MAGIC;
|
||||
sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
|
||||
ovl_trusted_xattr_handlers;
|
||||
sb->s_xattr = ovl_xattr_handlers(ofs);
|
||||
sb->s_fs_info = ofs;
|
||||
#ifdef CONFIG_FS_POSIX_ACL
|
||||
sb->s_flags |= SB_POSIXACL;
|
||||
|
196
fs/overlayfs/xattrs.c
Normal file
196
fs/overlayfs/xattrs.c
Normal file
@ -0,0 +1,196 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/xattr.h>
|
||||
#include "overlayfs.h"
|
||||
|
||||
bool ovl_is_private_xattr(struct super_block *sb, const char *name)
|
||||
{
|
||||
struct ovl_fs *ofs = OVL_FS(sb);
|
||||
|
||||
if (ofs->config.userxattr)
|
||||
return strncmp(name, OVL_XATTR_USER_PREFIX,
|
||||
sizeof(OVL_XATTR_USER_PREFIX) - 1) == 0;
|
||||
else
|
||||
return strncmp(name, OVL_XATTR_TRUSTED_PREFIX,
|
||||
sizeof(OVL_XATTR_TRUSTED_PREFIX) - 1) == 0;
|
||||
}
|
||||
|
||||
static int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
int err;
|
||||
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
|
||||
struct dentry *upperdentry = ovl_i_dentry_upper(inode);
|
||||
struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
|
||||
struct path realpath;
|
||||
const struct cred *old_cred;
|
||||
|
||||
if (!value && !upperdentry) {
|
||||
ovl_path_lower(dentry, &realpath);
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
|
||||
revert_creds(old_cred);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!upperdentry) {
|
||||
err = ovl_copy_up(dentry);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
realdentry = ovl_dentry_upper(dentry);
|
||||
}
|
||||
|
||||
err = ovl_want_write(dentry);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
if (value) {
|
||||
err = ovl_do_setxattr(ofs, realdentry, name, value, size,
|
||||
flags);
|
||||
} else {
|
||||
WARN_ON(flags != XATTR_REPLACE);
|
||||
err = ovl_do_removexattr(ofs, realdentry, name);
|
||||
}
|
||||
revert_creds(old_cred);
|
||||
ovl_drop_write(dentry);
|
||||
|
||||
/* copy c/mtime */
|
||||
ovl_copyattr(inode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
ssize_t res;
|
||||
const struct cred *old_cred;
|
||||
struct path realpath;
|
||||
|
||||
ovl_i_path_real(inode, &realpath);
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
res = vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size);
|
||||
revert_creds(old_cred);
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool ovl_can_list(struct super_block *sb, const char *s)
|
||||
{
|
||||
/* Never list private (.overlay) */
|
||||
if (ovl_is_private_xattr(sb, s))
|
||||
return false;
|
||||
|
||||
/* List all non-trusted xattrs */
|
||||
if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
|
||||
return true;
|
||||
|
||||
/* list other trusted for superuser only */
|
||||
return ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
|
||||
}
|
||||
|
||||
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
|
||||
{
|
||||
struct dentry *realdentry = ovl_dentry_real(dentry);
|
||||
ssize_t res;
|
||||
size_t len;
|
||||
char *s;
|
||||
const struct cred *old_cred;
|
||||
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
res = vfs_listxattr(realdentry, list, size);
|
||||
revert_creds(old_cred);
|
||||
if (res <= 0 || size == 0)
|
||||
return res;
|
||||
|
||||
/* filter out private xattrs */
|
||||
for (s = list, len = res; len;) {
|
||||
size_t slen = strnlen(s, len) + 1;
|
||||
|
||||
/* underlying fs providing us with an broken xattr list? */
|
||||
if (WARN_ON(slen > len))
|
||||
return -EIO;
|
||||
|
||||
len -= slen;
|
||||
if (!ovl_can_list(dentry->d_sb, s)) {
|
||||
res -= slen;
|
||||
memmove(s, s + slen, len);
|
||||
} else {
|
||||
s += slen;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ovl_own_xattr_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ovl_own_xattr_set(const struct xattr_handler *handler,
|
||||
struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ovl_other_xattr_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ovl_xattr_get(dentry, inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int ovl_other_xattr_set(const struct xattr_handler *handler,
|
||||
struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
return ovl_xattr_set(dentry, inode, name, value, size, flags);
|
||||
}
|
||||
|
||||
static const struct xattr_handler ovl_own_trusted_xattr_handler = {
|
||||
.prefix = OVL_XATTR_TRUSTED_PREFIX,
|
||||
.get = ovl_own_xattr_get,
|
||||
.set = ovl_own_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler ovl_own_user_xattr_handler = {
|
||||
.prefix = OVL_XATTR_USER_PREFIX,
|
||||
.get = ovl_own_xattr_get,
|
||||
.set = ovl_own_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler ovl_other_xattr_handler = {
|
||||
.prefix = "", /* catch all */
|
||||
.get = ovl_other_xattr_get,
|
||||
.set = ovl_other_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler * const ovl_trusted_xattr_handlers[] = {
|
||||
&ovl_own_trusted_xattr_handler,
|
||||
&ovl_other_xattr_handler,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct xattr_handler * const ovl_user_xattr_handlers[] = {
|
||||
&ovl_own_user_xattr_handler,
|
||||
&ovl_other_xattr_handler,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct xattr_handler * const *ovl_xattr_handlers(struct ovl_fs *ofs)
|
||||
{
|
||||
return ofs->config.userxattr ? ovl_user_xattr_handlers :
|
||||
ovl_trusted_xattr_handlers;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user