History

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.

Andrey Albershteyn committed 1 year ago

Commit be7efb21 parent 276e13621 files · +218 −1Browse files

Unified · Split

21 files
  1. arch/alpha/kernel/syscalls/syscall.tbl +2 −0
  2. arch/arm/tools/syscall.tbl +2 −0
  3. arch/arm64/tools/syscall_32.tbl +2 −0
  4. arch/m68k/kernel/syscalls/syscall.tbl +2 −0
  5. arch/microblaze/kernel/syscalls/syscall.tbl +2 −0
  6. arch/mips/kernel/syscalls/syscall_n32.tbl +2 −0
  7. arch/mips/kernel/syscalls/syscall_n64.tbl +2 −0
  8. arch/mips/kernel/syscalls/syscall_o32.tbl +2 −0
  9. arch/parisc/kernel/syscalls/syscall.tbl +2 −0
  10. arch/powerpc/kernel/syscalls/syscall.tbl +2 −0
  11. arch/s390/kernel/syscalls/syscall.tbl +2 −0
  12. arch/sh/kernel/syscalls/syscall.tbl +2 −0
  13. arch/sparc/kernel/syscalls/syscall.tbl +2 −0
  14. arch/x86/entry/syscalls/syscall_32.tbl +2 −0
  15. arch/x86/entry/syscalls/syscall_64.tbl +2 −0
  16. arch/xtensa/kernel/syscalls/syscall.tbl +2 −0
  17. fs/file_attr.c +152 −0
  18. include/linux/syscalls.h +7 −0
  19. include/uapi/asm-generic/unistd.h +7 −1
  20. include/uapi/linux/fs.h +18 −0
  21. scripts/syscall.tbl +2 −0
arch/alpha/kernel/syscalls/syscall.tbl+2−0
@@ -507,3 +507,5 @@ · 506 unmodified lines
507575 common listxattrat sys_listxattrat507575 common listxattrat sys_listxattrat
508576 common removexattrat sys_removexattrat508576 common removexattrat sys_removexattrat
509577 common open_tree_attr sys_open_tree_attr509577 common open_tree_attr sys_open_tree_attr
510578 common file_getattr sys_file_getattr
511579 common file_setattr sys_file_setattr
arch/arm/tools/syscall.tbl+2−0
@@ -482,3 +482,5 @@ · 481 unmodified lines
482465 common listxattrat sys_listxattrat482465 common listxattrat sys_listxattrat
483466 common removexattrat sys_removexattrat483466 common removexattrat sys_removexattrat
484467 common open_tree_attr sys_open_tree_attr484467 common open_tree_attr sys_open_tree_attr
485468 common file_getattr sys_file_getattr
486469 common file_setattr sys_file_setattr
arch/arm64/tools/syscall_32.tbl+2−0
@@ -479,3 +479,5 @@ · 478 unmodified lines
479465 common listxattrat sys_listxattrat479465 common listxattrat sys_listxattrat
480466 common removexattrat sys_removexattrat480466 common removexattrat sys_removexattrat
481467 common open_tree_attr sys_open_tree_attr481467 common open_tree_attr sys_open_tree_attr
482468 common file_getattr sys_file_getattr
483469 common file_setattr sys_file_setattr
arch/m68k/kernel/syscalls/syscall.tbl+2−0
@@ -467,3 +467,5 @@ · 466 unmodified lines
467465 common listxattrat sys_listxattrat467465 common listxattrat sys_listxattrat
468466 common removexattrat sys_removexattrat468466 common removexattrat sys_removexattrat
469467 common open_tree_attr sys_open_tree_attr469467 common open_tree_attr sys_open_tree_attr
470468 common file_getattr sys_file_getattr
471469 common file_setattr sys_file_setattr
arch/microblaze/kernel/syscalls/syscall.tbl+2−0
@@ -473,3 +473,5 @@ · 472 unmodified lines
473465 common listxattrat sys_listxattrat473465 common listxattrat sys_listxattrat
474466 common removexattrat sys_removexattrat474466 common removexattrat sys_removexattrat
475467 common open_tree_attr sys_open_tree_attr475467 common open_tree_attr sys_open_tree_attr
476468 common file_getattr sys_file_getattr
477469 common file_setattr sys_file_setattr
arch/mips/kernel/syscalls/syscall_n32.tbl+2−0
@@ -406,3 +406,5 @@ · 405 unmodified lines
406465 n32 listxattrat sys_listxattrat406465 n32 listxattrat sys_listxattrat
407466 n32 removexattrat sys_removexattrat407466 n32 removexattrat sys_removexattrat
408467 n32 open_tree_attr sys_open_tree_attr408467 n32 open_tree_attr sys_open_tree_attr
409468 n32 file_getattr sys_file_getattr
410469 n32 file_setattr sys_file_setattr
arch/mips/kernel/syscalls/syscall_n64.tbl+2−0
@@ -382,3 +382,5 @@ · 381 unmodified lines
382465 n64 listxattrat sys_listxattrat382465 n64 listxattrat sys_listxattrat
383466 n64 removexattrat sys_removexattrat383466 n64 removexattrat sys_removexattrat
384467 n64 open_tree_attr sys_open_tree_attr384467 n64 open_tree_attr sys_open_tree_attr
385468 n64 file_getattr sys_file_getattr
386469 n64 file_setattr sys_file_setattr
arch/mips/kernel/syscalls/syscall_o32.tbl+2−0
@@ -455,3 +455,5 @@ · 454 unmodified lines
455465 o32 listxattrat sys_listxattrat455465 o32 listxattrat sys_listxattrat
456466 o32 removexattrat sys_removexattrat456466 o32 removexattrat sys_removexattrat
457467 o32 open_tree_attr sys_open_tree_attr457467 o32 open_tree_attr sys_open_tree_attr
458468 o32 file_getattr sys_file_getattr
459469 o32 file_setattr sys_file_setattr
arch/parisc/kernel/syscalls/syscall.tbl+2−0
@@ -466,3 +466,5 @@ · 465 unmodified lines
466465 common listxattrat sys_listxattrat466465 common listxattrat sys_listxattrat
467466 common removexattrat sys_removexattrat467466 common removexattrat sys_removexattrat
468467 common open_tree_attr sys_open_tree_attr468467 common open_tree_attr sys_open_tree_attr
469468 common file_getattr sys_file_getattr
470469 common file_setattr sys_file_setattr
arch/powerpc/kernel/syscalls/syscall.tbl+2−0
@@ -558,3 +558,5 @@ · 557 unmodified lines
558465 common listxattrat sys_listxattrat558465 common listxattrat sys_listxattrat
559466 common removexattrat sys_removexattrat559466 common removexattrat sys_removexattrat
560467 common open_tree_attr sys_open_tree_attr560467 common open_tree_attr sys_open_tree_attr
561468 common file_getattr sys_file_getattr
562469 common file_setattr sys_file_setattr
arch/s390/kernel/syscalls/syscall.tbl+2−0
@@ -470,3 +470,5 @@ · 469 unmodified lines
470465 common listxattrat sys_listxattrat sys_listxattrat470465 common listxattrat sys_listxattrat sys_listxattrat
471466 common removexattrat sys_removexattrat sys_removexattrat471466 common removexattrat sys_removexattrat sys_removexattrat
472467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr472467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr
473468 common file_getattr sys_file_getattr sys_file_getattr
474469 common file_setattr sys_file_setattr sys_file_setattr
arch/sh/kernel/syscalls/syscall.tbl+2−0
@@ -471,3 +471,5 @@ · 470 unmodified lines
471465 common listxattrat sys_listxattrat471465 common listxattrat sys_listxattrat
472466 common removexattrat sys_removexattrat472466 common removexattrat sys_removexattrat
473467 common open_tree_attr sys_open_tree_attr473467 common open_tree_attr sys_open_tree_attr
474468 common file_getattr sys_file_getattr
475469 common file_setattr sys_file_setattr
arch/sparc/kernel/syscalls/syscall.tbl+2−0
@@ -513,3 +513,5 @@ · 512 unmodified lines
513465 common listxattrat sys_listxattrat513465 common listxattrat sys_listxattrat
514466 common removexattrat sys_removexattrat514466 common removexattrat sys_removexattrat
515467 common open_tree_attr sys_open_tree_attr515467 common open_tree_attr sys_open_tree_attr
516468 common file_getattr sys_file_getattr
517469 common file_setattr sys_file_setattr
arch/x86/entry/syscalls/syscall_32.tbl+2−0
@@ -473,3 +473,5 @@ · 472 unmodified lines
473465 i386 listxattrat sys_listxattrat473465 i386 listxattrat sys_listxattrat
474466 i386 removexattrat sys_removexattrat474466 i386 removexattrat sys_removexattrat
475467 i386 open_tree_attr sys_open_tree_attr475467 i386 open_tree_attr sys_open_tree_attr
476468 i386 file_getattr sys_file_getattr
477469 i386 file_setattr sys_file_setattr
arch/x86/entry/syscalls/syscall_64.tbl+2−0
@@ -391,6 +391,8 @@ · 390 unmodified lines
391465 common listxattrat sys_listxattrat391465 common listxattrat sys_listxattrat
392466 common removexattrat sys_removexattrat392466 common removexattrat sys_removexattrat
393467 common open_tree_attr sys_open_tree_attr393467 common open_tree_attr sys_open_tree_attr
394468 common file_getattr sys_file_getattr
395469 common file_setattr sys_file_setattr
394 396
395#397#
396# Due to a historical design error, certain syscalls are numbered differently398# Due to a historical design error, certain syscalls are numbered differently
arch/xtensa/kernel/syscalls/syscall.tbl+2−0
@@ -438,3 +438,5 @@ · 437 unmodified lines
438465 common listxattrat sys_listxattrat438465 common listxattrat sys_listxattrat
439466 common removexattrat sys_removexattrat439466 common removexattrat sys_removexattrat
440467 common open_tree_attr sys_open_tree_attr440467 common open_tree_attr sys_open_tree_attr
441468 common file_getattr sys_file_getattr
442469 common file_setattr sys_file_setattr
fs/file_attr.c+152−0
@@ -4,6 +4,10 @@ · 3 unmodified lines
4#include <linux/fscrypt.h>4#include <linux/fscrypt.h>
5#include <linux/fileattr.h>5#include <linux/fileattr.h>
6#include <linux/export.h>6#include <linux/export.h>
7#include <linux/syscalls.h>
8#include <linux/namei.h>
9
10#include "internal.h"
7 11
8/**12/**
9 * fileattr_fill_xflags - initialize fileattr with xflags13 * fileattr_fill_xflags - initialize fileattr with xflags
@@ -90,6 +94,19 @@ int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) · 80 unmodified lines
90}94}
91EXPORT_SYMBOL(vfs_fileattr_get);95EXPORT_SYMBOL(vfs_fileattr_get);
92 96
97static void fileattr_to_file_attr(const struct fileattr *fa,
98 struct file_attr *fattr)
99{
100 __u32 mask = FS_XFLAGS_MASK;
101
102 memset(fattr, 0, sizeof(struct file_attr));
103 fattr->fa_xflags = fa->fsx_xflags & mask;
104 fattr->fa_extsize = fa->fsx_extsize;
105 fattr->fa_nextents = fa->fsx_nextents;
106 fattr->fa_projid = fa->fsx_projid;
107 fattr->fa_cowextsize = fa->fsx_cowextsize;
108}
109
93/**110/**
94 * copy_fsxattr_to_user - copy fsxattr to userspace.111 * copy_fsxattr_to_user - copy fsxattr to userspace.
95 * @fa: fileattr pointer112 * @fa: fileattr pointer
@@ -116,6 +133,23 @@ int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa) · 20 unmodified lines
116}133}
117EXPORT_SYMBOL(copy_fsxattr_to_user);134EXPORT_SYMBOL(copy_fsxattr_to_user);
118 135
136static int file_attr_to_fileattr(const struct file_attr *fattr,
137 struct fileattr *fa)
138{
139 __u32 mask = FS_XFLAGS_MASK;
140
141 if (fattr->fa_xflags & ~mask)
142 return -EINVAL;
143
144 fileattr_fill_xflags(fa, fattr->fa_xflags);
145 fa->fsx_xflags &= ~FS_XFLAG_RDONLY_MASK;
146 fa->fsx_extsize = fattr->fa_extsize;
147 fa->fsx_projid = fattr->fa_projid;
148 fa->fsx_cowextsize = fattr->fa_cowextsize;
149
150 return 0;
151}
152
119static int copy_fsxattr_from_user(struct fileattr *fa,153static int copy_fsxattr_from_user(struct fileattr *fa,
120 struct fsxattr __user *ufa)154 struct fsxattr __user *ufa)
121{155{
@@ -344,3 +378,121 @@ int ioctl_fssetxattr(struct file *file, void __user *argp) · 222 unmodified lines
344 return err;378 return err;
345}379}
346EXPORT_SYMBOL(ioctl_fssetxattr);380EXPORT_SYMBOL(ioctl_fssetxattr);
381
382SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
383 struct file_attr __user *, ufattr, size_t, usize,
384 unsigned int, at_flags)
385{
386 struct path filepath __free(path_put) = {};
387 struct filename *name __free(putname) = NULL;
388 unsigned int lookup_flags = 0;
389 struct file_attr fattr;
390 struct fileattr fa;
391 int error;
392
393 BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
394 BUILD_BUG_ON(sizeof(struct file_attr) != FILE_ATTR_SIZE_LATEST);
395
396 if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
397 return -EINVAL;
398
399 if (!(at_flags & AT_SYMLINK_NOFOLLOW))
400 lookup_flags |= LOOKUP_FOLLOW;
401
402 if (usize > PAGE_SIZE)
403 return -E2BIG;
404
405 if (usize < FILE_ATTR_SIZE_VER0)
406 return -EINVAL;
407
408 name = getname_maybe_null(filename, at_flags);
409 if (IS_ERR(name))
410 return PTR_ERR(name);
411
412 if (!name && dfd >= 0) {
413 CLASS(fd, f)(dfd);
414 if (fd_empty(f))
415 return -EBADF;
416
417 filepath = fd_file(f)->f_path;
418 path_get(&filepath);
419 } else {
420 error = filename_lookup(dfd, name, lookup_flags, &filepath,
421 NULL);
422 if (error)
423 return error;
424 }
425
426 error = vfs_fileattr_get(filepath.dentry, &fa);
427 if (error)
428 return error;
429
430 fileattr_to_file_attr(&fa, &fattr);
431 error = copy_struct_to_user(ufattr, usize, &fattr,
432 sizeof(struct file_attr), NULL);
433
434 return error;
435}
436
437SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
438 struct file_attr __user *, ufattr, size_t, usize,
439 unsigned int, at_flags)
440{
441 struct path filepath __free(path_put) = {};
442 struct filename *name __free(putname) = NULL;
443 unsigned int lookup_flags = 0;
444 struct file_attr fattr;
445 struct fileattr fa;
446 int error;
447
448 BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
449 BUILD_BUG_ON(sizeof(struct file_attr) != FILE_ATTR_SIZE_LATEST);
450
451 if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
452 return -EINVAL;
453
454 if (!(at_flags & AT_SYMLINK_NOFOLLOW))
455 lookup_flags |= LOOKUP_FOLLOW;
456
457 if (usize > PAGE_SIZE)
458 return -E2BIG;
459
460 if (usize < FILE_ATTR_SIZE_VER0)
461 return -EINVAL;
462
463 error = copy_struct_from_user(&fattr, sizeof(struct file_attr), ufattr,
464 usize);
465 if (error)
466 return error;
467
468 error = file_attr_to_fileattr(&fattr, &fa);
469 if (error)
470 return error;
471
472 name = getname_maybe_null(filename, at_flags);
473 if (IS_ERR(name))
474 return PTR_ERR(name);
475
476 if (!name && dfd >= 0) {
477 CLASS(fd, f)(dfd);
478 if (fd_empty(f))
479 return -EBADF;
480
481 filepath = fd_file(f)->f_path;
482 path_get(&filepath);
483 } else {
484 error = filename_lookup(dfd, name, lookup_flags, &filepath,
485 NULL);
486 if (error)
487 return error;
488 }
489
490 error = mnt_want_write(filepath.mnt);
491 if (!error) {
492 error = vfs_fileattr_set(mnt_idmap(filepath.mnt),
493 filepath.dentry, &fa);
494 mnt_drop_write(filepath.mnt);
495 }
496
497 return error;
498}
include/linux/syscalls.h+7−0
@@ -78,6 +78,7 @@ struct cachestat; · 77 unmodified lines
78struct statmount;78struct statmount;
79struct mnt_id_req;79struct mnt_id_req;
80struct xattr_args;80struct xattr_args;
81struct file_attr;
81 82
82#include <linux/types.h>83#include <linux/types.h>
83#include <linux/aio_abi.h>84#include <linux/aio_abi.h>
@@ -371,6 +372,12 @@ asmlinkage long sys_removexattrat(int dfd, const char __user *path, · 287 unmodified lines
371asmlinkage long sys_lremovexattr(const char __user *path,372asmlinkage long sys_lremovexattr(const char __user *path,
372 const char __user *name);373 const char __user *name);
373asmlinkage long sys_fremovexattr(int fd, const char __user *name);374asmlinkage long sys_fremovexattr(int fd, const char __user *name);
375asmlinkage long sys_file_getattr(int dfd, const char __user *filename,
376 struct file_attr __user *attr, size_t usize,
377 unsigned int at_flags);
378asmlinkage long sys_file_setattr(int dfd, const char __user *filename,
379 struct file_attr __user *attr, size_t usize,
380 unsigned int at_flags);
374asmlinkage long sys_getcwd(char __user *buf, unsigned long size);381asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
375asmlinkage long sys_eventfd2(unsigned int count, int flags);382asmlinkage long sys_eventfd2(unsigned int count, int flags);
376asmlinkage long sys_epoll_create1(int flags);383asmlinkage long sys_epoll_create1(int flags);
include/uapi/asm-generic/unistd.h+7−1
@@ -852,8 +852,14 @@ __SYSCALL(__NR_removexattrat, sys_removexattrat) · 851 unmodified lines
852#define __NR_open_tree_attr 467852#define __NR_open_tree_attr 467
853__SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)853__SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)
854 854
855/* fs/inode.c */
856#define __NR_file_getattr 468
857__SYSCALL(__NR_file_getattr, sys_file_getattr)
858#define __NR_file_setattr 469
859__SYSCALL(__NR_file_setattr, sys_file_setattr)
860
855#undef __NR_syscalls861#undef __NR_syscalls
856#define __NR_syscalls 468862#define __NR_syscalls 470
857 863
858/*864/*
859 * 32 bit systems traditionally used different865 * 32 bit systems traditionally used different
include/uapi/linux/fs.h+18−0
@@ -148,6 +148,24 @@ struct fsxattr { · 147 unmodified lines
148 unsigned char fsx_pad[8];148 unsigned char fsx_pad[8];
149};149};
150 150
151/*
152 * Variable size structure for file_[sg]et_attr().
153 *
154 * Note. This is alternative to the structure 'struct fileattr'/'struct fsxattr'.
155 * As this structure is passed to/from userspace with its size, this can
156 * be versioned based on the size.
157 */
158struct file_attr {
159 __u64 fa_xflags; /* xflags field value (get/set) */
160 __u32 fa_extsize; /* extsize field value (get/set)*/
161 __u32 fa_nextents; /* nextents field value (get) */
162 __u32 fa_projid; /* project identifier (get/set) */
163 __u32 fa_cowextsize; /* CoW extsize field value (get/set) */
164};
165
166#define FILE_ATTR_SIZE_VER0 24
167#define FILE_ATTR_SIZE_LATEST FILE_ATTR_SIZE_VER0
168
151/*169/*
152 * Flags for the fsx_xflags field170 * Flags for the fsx_xflags field
153 */171 */
scripts/syscall.tbl+2−0
@@ -408,3 +408,5 @@ · 407 unmodified lines
408465 common listxattrat sys_listxattrat408465 common listxattrat sys_listxattrat
409466 common removexattrat sys_removexattrat409466 common removexattrat sys_removexattrat
410467 common open_tree_attr sys_open_tree_attr410467 common open_tree_attr sys_open_tree_attr
411468 common file_getattr sys_file_getattr
412469 common file_setattr sys_file_setattr