From: Andrey Albershteyn <aalbe...@redhat.com>

Introduce file_getattr and file_setattr syscalls to manipulate inode
extended attributes/flags. The syscalls take parent directory fd and
path to the child together with struct fsxattr.

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-...@vger.kernel.org
CC: linux-fsde...@vger.kernel.org
CC: linux-...@vger.kernel.org
Signed-off-by: Andrey Albershteyn <aalbe...@kernel.org>
Acked-by: Arnd Bergmann <a...@arndb.de>
---
 arch/alpha/kernel/syscalls/syscall.tbl      |   2 +
 arch/arm/tools/syscall.tbl                  |   2 +
 arch/arm64/tools/syscall_32.tbl             |   2 +
 arch/m68k/kernel/syscalls/syscall.tbl       |   2 +
 arch/microblaze/kernel/syscalls/syscall.tbl |   2 +
 arch/mips/kernel/syscalls/syscall_n32.tbl   |   2 +
 arch/mips/kernel/syscalls/syscall_n64.tbl   |   2 +
 arch/mips/kernel/syscalls/syscall_o32.tbl   |   2 +
 arch/parisc/kernel/syscalls/syscall.tbl     |   2 +
 arch/powerpc/kernel/syscalls/syscall.tbl    |   2 +
 arch/s390/kernel/syscalls/syscall.tbl       |   2 +
 arch/sh/kernel/syscalls/syscall.tbl         |   2 +
 arch/sparc/kernel/syscalls/syscall.tbl      |   2 +
 arch/x86/entry/syscalls/syscall_32.tbl      |   2 +
 arch/x86/entry/syscalls/syscall_64.tbl      |   2 +
 arch/xtensa/kernel/syscalls/syscall.tbl     |   2 +
 fs/file_attr.c                              | 119 ++++++++++++++++++++++++++++
 include/linux/syscalls.h                    |   6 ++
 include/uapi/asm-generic/unistd.h           |   8 +-
 include/uapi/linux/fs.h                     |   3 +
 20 files changed, 167 insertions(+), 1 deletion(-)

diff --git a/arch/alpha/kernel/syscalls/syscall.tbl 
b/arch/alpha/kernel/syscalls/syscall.tbl
index 
2dd6340de6b4efddc406f0c235701c15cf02f650..16dca28ebf17e5df2230f640f3686835dc5a1f76
 100644
--- a/arch/alpha/kernel/syscalls/syscall.tbl
+++ b/arch/alpha/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl
index 
27c1d5ebcd91c8c296dc6676307f66bfdf4ab78d..b07e699aaa3c2840452109c0004529fc68e153ac
 100644
--- a/arch/arm/tools/syscall.tbl
+++ b/arch/arm/tools/syscall.tbl
@@ -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
diff --git a/arch/arm64/tools/syscall_32.tbl b/arch/arm64/tools/syscall_32.tbl
index 
0765b3a8d6d600d7b9f83182d401d9f80c03476c..8d9088bc577df0c6dba6d5d0c227585283789a3f
 100644
--- a/arch/arm64/tools/syscall_32.tbl
+++ b/arch/arm64/tools/syscall_32.tbl
@@ -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
diff --git a/arch/m68k/kernel/syscalls/syscall.tbl 
b/arch/m68k/kernel/syscalls/syscall.tbl
index 
9fe47112c586f152662af38a9a7f90957cb96cf8..f41d38dfbf1382339316f4e3e6e79c75dc2804ec
 100644
--- a/arch/m68k/kernel/syscalls/syscall.tbl
+++ b/arch/m68k/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl 
b/arch/microblaze/kernel/syscalls/syscall.tbl
index 
7b6e97828e552d4da90046ddfcd4a55723e522bb..580af574fe733af29ea69f40ae6e902ad2166ab2
 100644
--- a/arch/microblaze/kernel/syscalls/syscall.tbl
+++ b/arch/microblaze/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl 
b/arch/mips/kernel/syscalls/syscall_n32.tbl
index 
aa70e371bb54ab5d9c8dd8923b6ecf9693ee914d..d824ffe9a01496a13194710d5278dcc443e40894
 100644
--- a/arch/mips/kernel/syscalls/syscall_n32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n32.tbl
@@ -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
diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl 
b/arch/mips/kernel/syscalls/syscall_n64.tbl
index 
1e8c44c7b61492eabf00c777831e457a7a6e579c..7a7049c2c307885fe8be33aedb503cfe8afbfb24
 100644
--- a/arch/mips/kernel/syscalls/syscall_n64.tbl
+++ b/arch/mips/kernel/syscalls/syscall_n64.tbl
@@ -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
diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl 
b/arch/mips/kernel/syscalls/syscall_o32.tbl
index 
114a5a1a62302e32dd74d1679ff423a2d57c3c6b..d330274f06010c9f9bf80d55898d0bd38994ef58
 100644
--- a/arch/mips/kernel/syscalls/syscall_o32.tbl
+++ b/arch/mips/kernel/syscalls/syscall_o32.tbl
@@ -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
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl 
b/arch/parisc/kernel/syscalls/syscall.tbl
index 
94df3cb957e9d547d192e8732c0cf23ef2b5ce5d..88a788a7b18d17967019098b33d2be48a430aed3
 100644
--- a/arch/parisc/kernel/syscalls/syscall.tbl
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl 
b/arch/powerpc/kernel/syscalls/syscall.tbl
index 
9a084bdb892694bc562f514b55212d167cbac12f..b453e80dfc003796a08f022f6bd44cf76a5f82ab
 100644
--- a/arch/powerpc/kernel/syscalls/syscall.tbl
+++ b/arch/powerpc/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/s390/kernel/syscalls/syscall.tbl 
b/arch/s390/kernel/syscalls/syscall.tbl
index 
a4569b96ef06c54ce7aa795d039541c90a38284f..8a6744d658db3986f0ac0fd3c90592cdbd27249c
 100644
--- a/arch/s390/kernel/syscalls/syscall.tbl
+++ b/arch/s390/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/sh/kernel/syscalls/syscall.tbl 
b/arch/sh/kernel/syscalls/syscall.tbl
index 
52a7652fcff6394b96ace1f3b0ed72250ee5e669..5e9c9eff5539e24113bb757f1e5b51bd7c32864e
 100644
--- a/arch/sh/kernel/syscalls/syscall.tbl
+++ b/arch/sh/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/sparc/kernel/syscalls/syscall.tbl 
b/arch/sparc/kernel/syscalls/syscall.tbl
index 
83e45eb6c095a36baaf749927628e6052fe900e6..ebb7d06d1044fa9b113b0a3fe0316c77f48fc3d0
 100644
--- a/arch/sparc/kernel/syscalls/syscall.tbl
+++ b/arch/sparc/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl 
b/arch/x86/entry/syscalls/syscall_32.tbl
index 
ac007ea00979dc28b0ef7c002a0615ce86dd3101..4877e16da69a50f2225088e556661051dbe3c7a3
 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -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
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl 
b/arch/x86/entry/syscalls/syscall_64.tbl
index 
cfb5ca41e30de1a4e073750096f5b51a2ec137d2..92cf0fe2291eb99b536e4de4201aec16b3472094
 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -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
diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl 
b/arch/xtensa/kernel/syscalls/syscall.tbl
index 
f657a77314f8667fa019a01e10c84ea270024adc..374e4cb788d8a6d4e1f3358b949ea8b600013e1c
 100644
--- a/arch/xtensa/kernel/syscalls/syscall.tbl
+++ b/arch/xtensa/kernel/syscalls/syscall.tbl
@@ -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
diff --git a/fs/file_attr.c b/fs/file_attr.c
index 
6cd1e820f7b108c12c06654df843104f460b94cf..791a97bb2b612b2a0f2c06b7cfb41bac469ea5d1
 100644
--- a/fs/file_attr.c
+++ b/fs/file_attr.c
@@ -3,6 +3,10 @@
 #include <linux/security.h>
 #include <linux/fscrypt.h>
 #include <linux/fileattr.h>
+#include <linux/syscalls.h>
+#include <linux/namei.h>
+
+#include "internal.h"
 
 /**
  * fileattr_fill_xflags - initialize fileattr with xflags
@@ -354,3 +358,118 @@ 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 fsxattr __user *, ufsx, size_t, usize,
+               unsigned int, at_flags)
+{
+       struct fileattr fa = {};
+       struct path filepath __free(path_put) = {};
+       int error;
+       unsigned int lookup_flags = 0;
+       struct filename *name;
+       struct fsxattr fsx = {};
+
+       BUILD_BUG_ON(sizeof(struct fsxattr) < FSXATTR_SIZE_VER0);
+       BUILD_BUG_ON(sizeof(struct fsxattr) != FSXATTR_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 < FSXATTR_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);
+
+               filepath = fd_file(f)->f_path;
+               path_get(&filepath);
+       } else {
+               error = filename_lookup(dfd, name, lookup_flags, &filepath,
+                                       NULL);
+               putname(name);
+               if (error)
+                       return error;
+       }
+
+       error = vfs_fileattr_get(filepath.dentry, &fa);
+       if (error)
+               return error;
+
+       fileattr_to_fsxattr(&fa, &fsx);
+       error = copy_struct_to_user(ufsx, usize, &fsx, sizeof(struct fsxattr),
+                                   NULL);
+
+       return error;
+}
+
+SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
+               struct fsxattr __user *, ufsx, size_t, usize,
+               unsigned int, at_flags)
+{
+       struct fileattr fa;
+       struct path filepath __free(path_put) = {};
+       int error;
+       unsigned int lookup_flags = 0;
+       struct filename *name;
+       struct fsxattr fsx = {};
+
+       BUILD_BUG_ON(sizeof(struct fsxattr) < FSXATTR_SIZE_VER0);
+       BUILD_BUG_ON(sizeof(struct fsxattr) != FSXATTR_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 < FSXATTR_SIZE_VER0)
+               return -EINVAL;
+
+       error = copy_struct_from_user(&fsx, sizeof(struct fsxattr), ufsx, 
usize);
+       if (error)
+               return error;
+
+       error = fsxattr_to_fileattr(&fsx, &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);
+
+               filepath = fd_file(f)->f_path;
+               path_get(&filepath);
+       } else {
+               error = filename_lookup(dfd, name, lookup_flags, &filepath,
+                                       NULL);
+               putname(name);
+               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;
+}
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 
e5603cc91963dabb79324d6e9e2274f327311245..f2a747479718f9c93f6a448cdab2e60f7ee87709
 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -371,6 +371,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 fsxattr __user *ufsx, size_t usize,
+                                unsigned int at_flags);
+asmlinkage long sys_file_setattr(int dfd, const char __user *filename,
+                                struct fsxattr __user *ufsx, 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);
diff --git a/include/uapi/asm-generic/unistd.h 
b/include/uapi/asm-generic/unistd.h
index 
2892a45023af6d3eb941623d4fed04841ab07e02..04e0077fb4c97a4d565da86d3d0d1d243f32336e
 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -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
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index 
e762e1af650c4bf08766ba7a8ab7a2288e987039..bc1467b44b80e1db3527dd1b70f1a3a3ca7e4484
 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -148,6 +148,9 @@ struct fsxattr {
        unsigned char   fsx_pad[8];
 };
 
+#define FSXATTR_SIZE_VER0 28
+#define FSXATTR_SIZE_LATEST FSXATTR_SIZE_VER0
+
 /*
  * Flags for the fsx_xflags field
  */

-- 
2.47.2


Reply via email to