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
|
||||
576 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 n32 removexattrat sys_removexattrat
|
||||
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
|
||||
466 n64 removexattrat sys_removexattrat
|
||||
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
|
||||
466 o32 removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
466 i386 removexattrat sys_removexattrat
|
||||
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
|
||||
466 common removexattrat sys_removexattrat
|
||||
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
|
||||
|
|
|
@ -438,3 +438,5 @@
|
|||
465 common listxattrat sys_listxattrat
|
||||
466 common removexattrat sys_removexattrat
|
||||
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/fileattr.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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.
|
||||
* @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);
|
||||
|
||||
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,
|
||||
struct fsxattr __user *ufa)
|
||||
{
|
||||
|
@ -344,3 +378,121 @@ int ioctl_fssetxattr(struct file *file, void __user *argp)
|
|||
return err;
|
||||
}
|
||||
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 mnt_id_req;
|
||||
struct xattr_args;
|
||||
struct file_attr;
|
||||
|
||||
#include <linux/types.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,
|
||||
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_eventfd2(unsigned int count, int flags);
|
||||
asmlinkage long sys_epoll_create1(int flags);
|
||||
|
|
|
@ -852,8 +852,14 @@ __SYSCALL(__NR_removexattrat, sys_removexattrat)
|
|||
#define __NR_open_tree_attr 467
|
||||
__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
|
||||
#define __NR_syscalls 468
|
||||
#define __NR_syscalls 470
|
||||
|
||||
/*
|
||||
* 32 bit systems traditionally used different
|
||||
|
|
|
@ -148,6 +148,24 @@ struct fsxattr {
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -408,3 +408,5 @@
|
|||
465 common listxattrat sys_listxattrat
|
||||
466 common removexattrat sys_removexattrat
|
||||
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