mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
fs: introduce file_getattr and file_setattr syscalls
Introduce file_getattr() and file_setattr() syscalls to manipulate inode extended attributes. The syscalls takes pair of file descriptor and pathname. Then it operates on inode opened accroding to openat() semantics. The struct file_attr is passed to obtain/change extended attributes. This is an alternative to FS_IOC_FSSETXATTR ioctl with a difference that file don't need to be open as we can reference it with a path instead of fd. By having this we can manipulated inode extended attributes not only on regular files but also on special ones. This is not possible with FS_IOC_FSSETXATTR ioctl as with special files we can not call ioctl() directly on the filesystem inode using fd. This patch adds two new syscalls which allows userspace to get/set extended inode attributes on special files by using parent directory and a path - *at() like syscall. CC: linux-api@vger.kernel.org CC: linux-fsdevel@vger.kernel.org CC: linux-xfs@vger.kernel.org Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org> Link: https://lore.kernel.org/20250630-xattrat-syscall-v6-6-c4e3bc35227b@kernel.org Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
276e136bff
commit
be7efb2d20
21 changed files with 218 additions and 1 deletions
|
@ -507,3 +507,5 @@
|
||||||
575 common listxattrat sys_listxattrat
|
575 common listxattrat sys_listxattrat
|
||||||
576 common removexattrat sys_removexattrat
|
576 common removexattrat sys_removexattrat
|
||||||
577 common open_tree_attr sys_open_tree_attr
|
577 common open_tree_attr sys_open_tree_attr
|
||||||
|
578 common file_getattr sys_file_getattr
|
||||||
|
579 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -482,3 +482,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -479,3 +479,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -467,3 +467,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -473,3 +473,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -406,3 +406,5 @@
|
||||||
465 n32 listxattrat sys_listxattrat
|
465 n32 listxattrat sys_listxattrat
|
||||||
466 n32 removexattrat sys_removexattrat
|
466 n32 removexattrat sys_removexattrat
|
||||||
467 n32 open_tree_attr sys_open_tree_attr
|
467 n32 open_tree_attr sys_open_tree_attr
|
||||||
|
468 n32 file_getattr sys_file_getattr
|
||||||
|
469 n32 file_setattr sys_file_setattr
|
||||||
|
|
|
@ -382,3 +382,5 @@
|
||||||
465 n64 listxattrat sys_listxattrat
|
465 n64 listxattrat sys_listxattrat
|
||||||
466 n64 removexattrat sys_removexattrat
|
466 n64 removexattrat sys_removexattrat
|
||||||
467 n64 open_tree_attr sys_open_tree_attr
|
467 n64 open_tree_attr sys_open_tree_attr
|
||||||
|
468 n64 file_getattr sys_file_getattr
|
||||||
|
469 n64 file_setattr sys_file_setattr
|
||||||
|
|
|
@ -455,3 +455,5 @@
|
||||||
465 o32 listxattrat sys_listxattrat
|
465 o32 listxattrat sys_listxattrat
|
||||||
466 o32 removexattrat sys_removexattrat
|
466 o32 removexattrat sys_removexattrat
|
||||||
467 o32 open_tree_attr sys_open_tree_attr
|
467 o32 open_tree_attr sys_open_tree_attr
|
||||||
|
468 o32 file_getattr sys_file_getattr
|
||||||
|
469 o32 file_setattr sys_file_setattr
|
||||||
|
|
|
@ -466,3 +466,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -558,3 +558,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -470,3 +470,5 @@
|
||||||
465 common listxattrat sys_listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr sys_file_setattr
|
||||||
|
|
|
@ -471,3 +471,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -513,3 +513,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
|
@ -473,3 +473,5 @@
|
||||||
465 i386 listxattrat sys_listxattrat
|
465 i386 listxattrat sys_listxattrat
|
||||||
466 i386 removexattrat sys_removexattrat
|
466 i386 removexattrat sys_removexattrat
|
||||||
467 i386 open_tree_attr sys_open_tree_attr
|
467 i386 open_tree_attr sys_open_tree_attr
|
||||||
|
468 i386 file_getattr sys_file_getattr
|
||||||
|
469 i386 file_setattr sys_file_setattr
|
||||||
|
|
|
@ -391,6 +391,8 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
||||||
#
|
#
|
||||||
# Due to a historical design error, certain syscalls are numbered differently
|
# Due to a historical design error, certain syscalls are numbered differently
|
||||||
|
|
|
@ -438,3 +438,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
152
fs/file_attr.c
152
fs/file_attr.c
|
@ -4,6 +4,10 @@
|
||||||
#include <linux/fscrypt.h>
|
#include <linux/fscrypt.h>
|
||||||
#include <linux/fileattr.h>
|
#include <linux/fileattr.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/syscalls.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fileattr_fill_xflags - initialize fileattr with xflags
|
* fileattr_fill_xflags - initialize fileattr with xflags
|
||||||
|
@ -90,6 +94,19 @@ int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(vfs_fileattr_get);
|
EXPORT_SYMBOL(vfs_fileattr_get);
|
||||||
|
|
||||||
|
static void fileattr_to_file_attr(const struct fileattr *fa,
|
||||||
|
struct file_attr *fattr)
|
||||||
|
{
|
||||||
|
__u32 mask = FS_XFLAGS_MASK;
|
||||||
|
|
||||||
|
memset(fattr, 0, sizeof(struct file_attr));
|
||||||
|
fattr->fa_xflags = fa->fsx_xflags & mask;
|
||||||
|
fattr->fa_extsize = fa->fsx_extsize;
|
||||||
|
fattr->fa_nextents = fa->fsx_nextents;
|
||||||
|
fattr->fa_projid = fa->fsx_projid;
|
||||||
|
fattr->fa_cowextsize = fa->fsx_cowextsize;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* copy_fsxattr_to_user - copy fsxattr to userspace.
|
* copy_fsxattr_to_user - copy fsxattr to userspace.
|
||||||
* @fa: fileattr pointer
|
* @fa: fileattr pointer
|
||||||
|
@ -116,6 +133,23 @@ int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(copy_fsxattr_to_user);
|
EXPORT_SYMBOL(copy_fsxattr_to_user);
|
||||||
|
|
||||||
|
static int file_attr_to_fileattr(const struct file_attr *fattr,
|
||||||
|
struct fileattr *fa)
|
||||||
|
{
|
||||||
|
__u32 mask = FS_XFLAGS_MASK;
|
||||||
|
|
||||||
|
if (fattr->fa_xflags & ~mask)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
fileattr_fill_xflags(fa, fattr->fa_xflags);
|
||||||
|
fa->fsx_xflags &= ~FS_XFLAG_RDONLY_MASK;
|
||||||
|
fa->fsx_extsize = fattr->fa_extsize;
|
||||||
|
fa->fsx_projid = fattr->fa_projid;
|
||||||
|
fa->fsx_cowextsize = fattr->fa_cowextsize;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int copy_fsxattr_from_user(struct fileattr *fa,
|
static int copy_fsxattr_from_user(struct fileattr *fa,
|
||||||
struct fsxattr __user *ufa)
|
struct fsxattr __user *ufa)
|
||||||
{
|
{
|
||||||
|
@ -344,3 +378,121 @@ int ioctl_fssetxattr(struct file *file, void __user *argp)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ioctl_fssetxattr);
|
EXPORT_SYMBOL(ioctl_fssetxattr);
|
||||||
|
|
||||||
|
SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
|
||||||
|
struct file_attr __user *, ufattr, size_t, usize,
|
||||||
|
unsigned int, at_flags)
|
||||||
|
{
|
||||||
|
struct path filepath __free(path_put) = {};
|
||||||
|
struct filename *name __free(putname) = NULL;
|
||||||
|
unsigned int lookup_flags = 0;
|
||||||
|
struct file_attr fattr;
|
||||||
|
struct fileattr fa;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
|
||||||
|
BUILD_BUG_ON(sizeof(struct file_attr) != FILE_ATTR_SIZE_LATEST);
|
||||||
|
|
||||||
|
if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!(at_flags & AT_SYMLINK_NOFOLLOW))
|
||||||
|
lookup_flags |= LOOKUP_FOLLOW;
|
||||||
|
|
||||||
|
if (usize > PAGE_SIZE)
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
if (usize < FILE_ATTR_SIZE_VER0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
name = getname_maybe_null(filename, at_flags);
|
||||||
|
if (IS_ERR(name))
|
||||||
|
return PTR_ERR(name);
|
||||||
|
|
||||||
|
if (!name && dfd >= 0) {
|
||||||
|
CLASS(fd, f)(dfd);
|
||||||
|
if (fd_empty(f))
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
filepath = fd_file(f)->f_path;
|
||||||
|
path_get(&filepath);
|
||||||
|
} else {
|
||||||
|
error = filename_lookup(dfd, name, lookup_flags, &filepath,
|
||||||
|
NULL);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = vfs_fileattr_get(filepath.dentry, &fa);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
fileattr_to_file_attr(&fa, &fattr);
|
||||||
|
error = copy_struct_to_user(ufattr, usize, &fattr,
|
||||||
|
sizeof(struct file_attr), NULL);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
|
||||||
|
struct file_attr __user *, ufattr, size_t, usize,
|
||||||
|
unsigned int, at_flags)
|
||||||
|
{
|
||||||
|
struct path filepath __free(path_put) = {};
|
||||||
|
struct filename *name __free(putname) = NULL;
|
||||||
|
unsigned int lookup_flags = 0;
|
||||||
|
struct file_attr fattr;
|
||||||
|
struct fileattr fa;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
|
||||||
|
BUILD_BUG_ON(sizeof(struct file_attr) != FILE_ATTR_SIZE_LATEST);
|
||||||
|
|
||||||
|
if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!(at_flags & AT_SYMLINK_NOFOLLOW))
|
||||||
|
lookup_flags |= LOOKUP_FOLLOW;
|
||||||
|
|
||||||
|
if (usize > PAGE_SIZE)
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
if (usize < FILE_ATTR_SIZE_VER0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
error = copy_struct_from_user(&fattr, sizeof(struct file_attr), ufattr,
|
||||||
|
usize);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = file_attr_to_fileattr(&fattr, &fa);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
name = getname_maybe_null(filename, at_flags);
|
||||||
|
if (IS_ERR(name))
|
||||||
|
return PTR_ERR(name);
|
||||||
|
|
||||||
|
if (!name && dfd >= 0) {
|
||||||
|
CLASS(fd, f)(dfd);
|
||||||
|
if (fd_empty(f))
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
filepath = fd_file(f)->f_path;
|
||||||
|
path_get(&filepath);
|
||||||
|
} else {
|
||||||
|
error = filename_lookup(dfd, name, lookup_flags, &filepath,
|
||||||
|
NULL);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = mnt_want_write(filepath.mnt);
|
||||||
|
if (!error) {
|
||||||
|
error = vfs_fileattr_set(mnt_idmap(filepath.mnt),
|
||||||
|
filepath.dentry, &fa);
|
||||||
|
mnt_drop_write(filepath.mnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ struct cachestat;
|
||||||
struct statmount;
|
struct statmount;
|
||||||
struct mnt_id_req;
|
struct mnt_id_req;
|
||||||
struct xattr_args;
|
struct xattr_args;
|
||||||
|
struct file_attr;
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/aio_abi.h>
|
#include <linux/aio_abi.h>
|
||||||
|
@ -371,6 +372,12 @@ asmlinkage long sys_removexattrat(int dfd, const char __user *path,
|
||||||
asmlinkage long sys_lremovexattr(const char __user *path,
|
asmlinkage long sys_lremovexattr(const char __user *path,
|
||||||
const char __user *name);
|
const char __user *name);
|
||||||
asmlinkage long sys_fremovexattr(int fd, const char __user *name);
|
asmlinkage long sys_fremovexattr(int fd, const char __user *name);
|
||||||
|
asmlinkage long sys_file_getattr(int dfd, const char __user *filename,
|
||||||
|
struct file_attr __user *attr, size_t usize,
|
||||||
|
unsigned int at_flags);
|
||||||
|
asmlinkage long sys_file_setattr(int dfd, const char __user *filename,
|
||||||
|
struct file_attr __user *attr, size_t usize,
|
||||||
|
unsigned int at_flags);
|
||||||
asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
|
asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
|
||||||
asmlinkage long sys_eventfd2(unsigned int count, int flags);
|
asmlinkage long sys_eventfd2(unsigned int count, int flags);
|
||||||
asmlinkage long sys_epoll_create1(int flags);
|
asmlinkage long sys_epoll_create1(int flags);
|
||||||
|
|
|
@ -852,8 +852,14 @@ __SYSCALL(__NR_removexattrat, sys_removexattrat)
|
||||||
#define __NR_open_tree_attr 467
|
#define __NR_open_tree_attr 467
|
||||||
__SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)
|
__SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)
|
||||||
|
|
||||||
|
/* fs/inode.c */
|
||||||
|
#define __NR_file_getattr 468
|
||||||
|
__SYSCALL(__NR_file_getattr, sys_file_getattr)
|
||||||
|
#define __NR_file_setattr 469
|
||||||
|
__SYSCALL(__NR_file_setattr, sys_file_setattr)
|
||||||
|
|
||||||
#undef __NR_syscalls
|
#undef __NR_syscalls
|
||||||
#define __NR_syscalls 468
|
#define __NR_syscalls 470
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 32 bit systems traditionally used different
|
* 32 bit systems traditionally used different
|
||||||
|
|
|
@ -148,6 +148,24 @@ struct fsxattr {
|
||||||
unsigned char fsx_pad[8];
|
unsigned char fsx_pad[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variable size structure for file_[sg]et_attr().
|
||||||
|
*
|
||||||
|
* Note. This is alternative to the structure 'struct fileattr'/'struct fsxattr'.
|
||||||
|
* As this structure is passed to/from userspace with its size, this can
|
||||||
|
* be versioned based on the size.
|
||||||
|
*/
|
||||||
|
struct file_attr {
|
||||||
|
__u64 fa_xflags; /* xflags field value (get/set) */
|
||||||
|
__u32 fa_extsize; /* extsize field value (get/set)*/
|
||||||
|
__u32 fa_nextents; /* nextents field value (get) */
|
||||||
|
__u32 fa_projid; /* project identifier (get/set) */
|
||||||
|
__u32 fa_cowextsize; /* CoW extsize field value (get/set) */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FILE_ATTR_SIZE_VER0 24
|
||||||
|
#define FILE_ATTR_SIZE_LATEST FILE_ATTR_SIZE_VER0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags for the fsx_xflags field
|
* Flags for the fsx_xflags field
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -408,3 +408,5 @@
|
||||||
465 common listxattrat sys_listxattrat
|
465 common listxattrat sys_listxattrat
|
||||||
466 common removexattrat sys_removexattrat
|
466 common removexattrat sys_removexattrat
|
||||||
467 common open_tree_attr sys_open_tree_attr
|
467 common open_tree_attr sys_open_tree_attr
|
||||||
|
468 common file_getattr sys_file_getattr
|
||||||
|
469 common file_setattr sys_file_setattr
|
||||||
|
|
Loading…
Add table
Reference in a new issue