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
507507 575 common listxattrat sys_listxattrat
508508 576 common removexattrat sys_removexattrat
509509 577 common open_tree_attr sys_open_tree_attr
510+578 common file_getattr sys_file_getattr
511+579 common file_setattr sys_file_setattr
arch/arm/tools/syscall.tbl+2−0
@@ -482,3 +482,5 @@ · 481 unmodified lines
482482 465 common listxattrat sys_listxattrat
483483 466 common removexattrat sys_removexattrat
484484 467 common open_tree_attr sys_open_tree_attr
485+468 common file_getattr sys_file_getattr
486+469 common file_setattr sys_file_setattr
arch/arm64/tools/syscall_32.tbl+2−0
@@ -479,3 +479,5 @@ · 478 unmodified lines
479479 465 common listxattrat sys_listxattrat
480480 466 common removexattrat sys_removexattrat
481481 467 common open_tree_attr sys_open_tree_attr
482+468 common file_getattr sys_file_getattr
483+469 common file_setattr sys_file_setattr
arch/m68k/kernel/syscalls/syscall.tbl+2−0
@@ -467,3 +467,5 @@ · 466 unmodified lines
467467 465 common listxattrat sys_listxattrat
468468 466 common removexattrat sys_removexattrat
469469 467 common open_tree_attr sys_open_tree_attr
470+468 common file_getattr sys_file_getattr
471+469 common file_setattr sys_file_setattr
arch/microblaze/kernel/syscalls/syscall.tbl+2−0
@@ -473,3 +473,5 @@ · 472 unmodified lines
473473 465 common listxattrat sys_listxattrat
474474 466 common removexattrat sys_removexattrat
475475 467 common open_tree_attr sys_open_tree_attr
476+468 common file_getattr sys_file_getattr
477+469 common file_setattr sys_file_setattr
arch/mips/kernel/syscalls/syscall_n32.tbl+2−0
@@ -406,3 +406,5 @@ · 405 unmodified lines
406406 465 n32 listxattrat sys_listxattrat
407407 466 n32 removexattrat sys_removexattrat
408408 467 n32 open_tree_attr sys_open_tree_attr
409+468 n32 file_getattr sys_file_getattr
410+469 n32 file_setattr sys_file_setattr
arch/mips/kernel/syscalls/syscall_n64.tbl+2−0
@@ -382,3 +382,5 @@ · 381 unmodified lines
382382 465 n64 listxattrat sys_listxattrat
383383 466 n64 removexattrat sys_removexattrat
384384 467 n64 open_tree_attr sys_open_tree_attr
385+468 n64 file_getattr sys_file_getattr
386+469 n64 file_setattr sys_file_setattr
arch/mips/kernel/syscalls/syscall_o32.tbl+2−0
@@ -455,3 +455,5 @@ · 454 unmodified lines
455455 465 o32 listxattrat sys_listxattrat
456456 466 o32 removexattrat sys_removexattrat
457457 467 o32 open_tree_attr sys_open_tree_attr
458+468 o32 file_getattr sys_file_getattr
459+469 o32 file_setattr sys_file_setattr
arch/parisc/kernel/syscalls/syscall.tbl+2−0
@@ -466,3 +466,5 @@ · 465 unmodified lines
466466 465 common listxattrat sys_listxattrat
467467 466 common removexattrat sys_removexattrat
468468 467 common open_tree_attr sys_open_tree_attr
469+468 common file_getattr sys_file_getattr
470+469 common file_setattr sys_file_setattr
arch/powerpc/kernel/syscalls/syscall.tbl+2−0
@@ -558,3 +558,5 @@ · 557 unmodified lines
558558 465 common listxattrat sys_listxattrat
559559 466 common removexattrat sys_removexattrat
560560 467 common open_tree_attr sys_open_tree_attr
561+468 common file_getattr sys_file_getattr
562+469 common file_setattr sys_file_setattr
arch/s390/kernel/syscalls/syscall.tbl+2−0
@@ -470,3 +470,5 @@ · 469 unmodified lines
470470 465 common listxattrat sys_listxattrat sys_listxattrat
471471 466 common removexattrat sys_removexattrat sys_removexattrat
472472 467 common open_tree_attr sys_open_tree_attr sys_open_tree_attr
473+468 common file_getattr sys_file_getattr sys_file_getattr
474+469 common file_setattr sys_file_setattr sys_file_setattr
arch/sh/kernel/syscalls/syscall.tbl+2−0
@@ -471,3 +471,5 @@ · 470 unmodified lines
471471 465 common listxattrat sys_listxattrat
472472 466 common removexattrat sys_removexattrat
473473 467 common open_tree_attr sys_open_tree_attr
474+468 common file_getattr sys_file_getattr
475+469 common file_setattr sys_file_setattr
arch/sparc/kernel/syscalls/syscall.tbl+2−0
@@ -513,3 +513,5 @@ · 512 unmodified lines
513513 465 common listxattrat sys_listxattrat
514514 466 common removexattrat sys_removexattrat
515515 467 common open_tree_attr sys_open_tree_attr
516+468 common file_getattr sys_file_getattr
517+469 common file_setattr sys_file_setattr
arch/x86/entry/syscalls/syscall_32.tbl+2−0
@@ -473,3 +473,5 @@ · 472 unmodified lines
473473 465 i386 listxattrat sys_listxattrat
474474 466 i386 removexattrat sys_removexattrat
475475 467 i386 open_tree_attr sys_open_tree_attr
476+468 i386 file_getattr sys_file_getattr
477+469 i386 file_setattr sys_file_setattr
arch/x86/entry/syscalls/syscall_64.tbl+2−0
@@ -391,6 +391,8 @@ · 390 unmodified lines
391391 465 common listxattrat sys_listxattrat
392392 466 common removexattrat sys_removexattrat
393393 467 common open_tree_attr sys_open_tree_attr
394+468 common file_getattr sys_file_getattr
395+469 common file_setattr sys_file_setattr
394396
395397 #
396398 # 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
438438 465 common listxattrat sys_listxattrat
439439 466 common removexattrat sys_removexattrat
440440 467 common open_tree_attr sys_open_tree_attr
441+468 common file_getattr sys_file_getattr
442+469 common file_setattr sys_file_setattr
fs/file_attr.c+152−0
@@ -4,6 +4,10 @@ · 3 unmodified lines
44 #include <linux/fscrypt.h>
55 #include <linux/fileattr.h>
66 #include <linux/export.h>
7+#include <linux/syscalls.h>
8+#include <linux/namei.h>
9+
10+#include "internal.h"
711
812 /**
913 * fileattr_fill_xflags - initialize fileattr with xflags
@@ -90,6 +94,19 @@ int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) · 80 unmodified lines
9094 }
9195 EXPORT_SYMBOL(vfs_fileattr_get);
9296
97+static 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+
93110 /**
94111 * copy_fsxattr_to_user - copy fsxattr to userspace.
95112 * @fa: fileattr pointer
@@ -116,6 +133,23 @@ int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa) · 20 unmodified lines
116133 }
117134 EXPORT_SYMBOL(copy_fsxattr_to_user);
118135
136+static 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+
119153 static int copy_fsxattr_from_user(struct fileattr *fa,
120154 struct fsxattr __user *ufa)
121155 {
@@ -344,3 +378,121 @@ int ioctl_fssetxattr(struct file *file, void __user *argp) · 222 unmodified lines
344378 return err;
345379 }
346380 EXPORT_SYMBOL(ioctl_fssetxattr);
381+
382+SYSCALL_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+
437+SYSCALL_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
7878 struct statmount;
7979 struct mnt_id_req;
8080 struct xattr_args;
81+struct file_attr;
8182
8283 #include <linux/types.h>
8384 #include <linux/aio_abi.h>
@@ -371,6 +372,12 @@ asmlinkage long sys_removexattrat(int dfd, const char __user *path, · 287 unmodified lines
371372 asmlinkage long sys_lremovexattr(const char __user *path,
372373 const char __user *name);
373374 asmlinkage long sys_fremovexattr(int fd, const char __user *name);
375+asmlinkage long sys_file_getattr(int dfd, const char __user *filename,
376+ struct file_attr __user *attr, size_t usize,
377+ unsigned int at_flags);
378+asmlinkage long sys_file_setattr(int dfd, const char __user *filename,
379+ struct file_attr __user *attr, size_t usize,
380+ unsigned int at_flags);
374381 asmlinkage long sys_getcwd(char __user *buf, unsigned long size);
375382 asmlinkage long sys_eventfd2(unsigned int count, int flags);
376383 asmlinkage 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
852852 #define __NR_open_tree_attr 467
853853 __SYSCALL(__NR_open_tree_attr, sys_open_tree_attr)
854854
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+
855861 #undef __NR_syscalls
856−#define __NR_syscalls 468
862+#define __NR_syscalls 470
857863
858864 /*
859865 * 32 bit systems traditionally used different
include/uapi/linux/fs.h+18−0
@@ -148,6 +148,24 @@ struct fsxattr { · 147 unmodified lines
148148 unsigned char fsx_pad[8];
149149 };
150150
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+ */
158+struct 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+
151169 /*
152170 * Flags for the fsx_xflags field
153171 */
scripts/syscall.tbl+2−0
@@ -408,3 +408,5 @@ · 407 unmodified lines
408408 465 common listxattrat sys_listxattrat
409409 466 common removexattrat sys_removexattrat
410410 467 common open_tree_attr sys_open_tree_attr
411+468 common file_getattr sys_file_getattr
412+469 common file_setattr sys_file_setattr