Message ID | 20250109174540.893098-1-aalbersh@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | fs: introduce getfsxattrat and setfsxattrat syscalls | expand |
On Thu, Jan 9, 2025, at 18:45, Andrey Albershteyn wrote: > > arch/alpha/kernel/syscalls/syscall.tbl | 2 + > arch/m68k/kernel/syscalls/syscall.tbl | 2 + > arch/microblaze/kernel/syscalls/syscall.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 + You seem to be missing a couple of files here: arch/arm/tools/syscall.tbl arch/arm64/tools/syscall_32.tbl arch/mips/kernel/syscalls/syscall_n32.tbl arch/mips/kernel/syscalls/syscall_n64.tbl arch/mips/kernel/syscalls/syscall_o32.tbl Arnd
On 2025-01-09 20:59:45, Arnd Bergmann wrote: > On Thu, Jan 9, 2025, at 18:45, Andrey Albershteyn wrote: > > > > arch/alpha/kernel/syscalls/syscall.tbl | 2 + > > arch/m68k/kernel/syscalls/syscall.tbl | 2 + > > arch/microblaze/kernel/syscalls/syscall.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 + > > You seem to be missing a couple of files here: > > arch/arm/tools/syscall.tbl > arch/arm64/tools/syscall_32.tbl > arch/mips/kernel/syscalls/syscall_n32.tbl > arch/mips/kernel/syscalls/syscall_n64.tbl > arch/mips/kernel/syscalls/syscall_o32.tbl > > Arnd > Thanks! Added
Hi Andrey, kernel test robot noticed the following build warnings: [auto build test WARNING on brauner-vfs/vfs.all] [also build test WARNING on geert-m68k/for-next powerpc/next powerpc/fixes s390/features linus/master v6.13-rc6 next-20250110] [cannot apply to geert-m68k/for-linus deller-parisc/for-next jcmvbkbc-xtensa/xtensa-for-next arnd-asm-generic/master tip/x86/asm] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Andrey-Albershteyn/fs-introduce-getfsxattrat-and-setfsxattrat-syscalls/20250110-014739 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250109174540.893098-1-aalbersh%40kernel.org patch subject: [PATCH] fs: introduce getfsxattrat and setfsxattrat syscalls config: arm-allnoconfig (https://download.01.org/0day-ci/archive/20250111/202501112052.ZJEvfjhd-lkp@intel.com/config) compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250111/202501112052.ZJEvfjhd-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202501112052.ZJEvfjhd-lkp@intel.com/ All warnings (new ones prefixed by >>): >> <stdin>:1615:2: warning: syscall getfsxattrat not implemented [-W#warnings] 1615 | #warning syscall getfsxattrat not implemented | ^ >> <stdin>:1618:2: warning: syscall setfsxattrat not implemented [-W#warnings] 1618 | #warning syscall setfsxattrat not implemented | ^ 2 warnings generated. -- >> <stdin>:1615:2: warning: syscall getfsxattrat not implemented [-W#warnings] 1615 | #warning syscall getfsxattrat not implemented | ^ >> <stdin>:1618:2: warning: syscall setfsxattrat not implemented [-W#warnings] 1618 | #warning syscall setfsxattrat not implemented | ^ 2 warnings generated.
Hi Andrey, kernel test robot noticed the following build warnings: [auto build test WARNING on brauner-vfs/vfs.all] [also build test WARNING on geert-m68k/for-next powerpc/next powerpc/fixes s390/features linus/master v6.13-rc6 next-20250110] [cannot apply to geert-m68k/for-linus deller-parisc/for-next jcmvbkbc-xtensa/xtensa-for-next arnd-asm-generic/master tip/x86/asm] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Andrey-Albershteyn/fs-introduce-getfsxattrat-and-setfsxattrat-syscalls/20250110-014739 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250109174540.893098-1-aalbersh%40kernel.org patch subject: [PATCH] fs: introduce getfsxattrat and setfsxattrat syscalls config: s390-randconfig-r133-20250111 (https://download.01.org/0day-ci/archive/20250111/202501112305.EPQr5jnx-lkp@intel.com/config) compiler: s390-linux-gcc (GCC) 14.2.0 reproduce: (https://download.01.org/0day-ci/archive/20250111/202501112305.EPQr5jnx-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202501112305.EPQr5jnx-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) fs/inode.c:605:28: sparse: sparse: context imbalance in 'inode_wait_for_lru_isolating' - unexpected unlock fs/inode.c: note: in included file (through include/linux/wait.h, include/linux/wait_bit.h, include/linux/fs.h): include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true include/linux/list.h:83:21: sparse: sparse: self-comparison always evaluates to true fs/inode.c:999:28: sparse: sparse: context imbalance in 'inode_lru_isolate' - unexpected unlock fs/inode.c:1058:9: sparse: sparse: context imbalance in 'find_inode' - different lock contexts for basic block fs/inode.c:1099:9: sparse: sparse: context imbalance in 'find_inode_fast' - different lock contexts for basic block fs/inode.c:1829:5: sparse: sparse: context imbalance in 'insert_inode_locked' - wrong count at exit fs/inode.c:1947:20: sparse: sparse: context imbalance in 'iput_final' - unexpected unlock fs/inode.c:1961:6: sparse: sparse: context imbalance in 'iput' - wrong count at exit fs/inode.c:2494:17: sparse: sparse: context imbalance in '__wait_on_freeing_inode' - unexpected unlock >> fs/inode.c:2960:1: sparse: sparse: Using plain integer as NULL pointer >> fs/inode.c:2960:1: sparse: sparse: Using plain integer as NULL pointer >> fs/inode.c:2960:1: sparse: sparse: Using plain integer as NULL pointer >> fs/inode.c:2960:1: sparse: sparse: Using plain integer as NULL pointer fs/inode.c:2998:39: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct fsxattr [noderef] __user *ufa @@ got struct fsxattr *fsx @@ fs/inode.c:2998:39: sparse: expected struct fsxattr [noderef] __user *ufa fs/inode.c:2998:39: sparse: got struct fsxattr *fsx fs/inode.c:2998:39: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct fsxattr [noderef] __user *ufa @@ got struct fsxattr *fsx @@ fs/inode.c:2998:39: sparse: expected struct fsxattr [noderef] __user *ufa fs/inode.c:2998:39: sparse: got struct fsxattr *fsx fs/inode.c:3008:1: sparse: sparse: Using plain integer as NULL pointer fs/inode.c:3008:1: sparse: sparse: Using plain integer as NULL pointer fs/inode.c:3008:1: sparse: sparse: Using plain integer as NULL pointer fs/inode.c:3008:1: sparse: sparse: Using plain integer as NULL pointer fs/inode.c:3032:41: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct fsxattr [noderef] __user *ufa @@ got struct fsxattr *fsx @@ fs/inode.c:3032:41: sparse: expected struct fsxattr [noderef] __user *ufa fs/inode.c:3032:41: sparse: got struct fsxattr *fsx fs/inode.c:3032:41: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct fsxattr [noderef] __user *ufa @@ got struct fsxattr *fsx @@ fs/inode.c:3032:41: sparse: expected struct fsxattr [noderef] __user *ufa fs/inode.c:3032:41: sparse: got struct fsxattr *fsx vim +2960 fs/inode.c 2959 > 2960 SYSCALL_DEFINE4(getfsxattrat, int, dfd, const char __user *, filename, 2961 struct fsxattr *, fsx, int, at_flags) 2962 { 2963 struct fd dir; 2964 struct fileattr fa; 2965 struct path filepath; 2966 struct inode *inode; 2967 int error; 2968 2969 if (at_flags) 2970 return -EINVAL; 2971 2972 if (!capable(CAP_FOWNER)) 2973 return -EPERM; 2974 2975 dir = fdget(dfd); 2976 if (!fd_file(dir)) 2977 return -EBADF; 2978 2979 if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { 2980 error = -EBADF; 2981 goto out; 2982 } 2983 2984 error = user_path_at(dfd, filename, at_flags, &filepath); 2985 if (error) 2986 goto out; 2987 2988 inode = filepath.dentry->d_inode; 2989 if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { 2990 error = -EBADF; 2991 goto out_path; 2992 } 2993 2994 error = vfs_fileattr_get(filepath.dentry, &fa); 2995 if (error) 2996 goto out_path; 2997 2998 if (copy_fsxattr_to_user(&fa, fsx)) 2999 error = -EFAULT; 3000 3001 out_path: 3002 path_put(&filepath); 3003 out: 3004 fdput(dir); 3005 return error; 3006 } 3007
Hi Andrey, kernel test robot noticed the following build warnings: [auto build test WARNING on brauner-vfs/vfs.all] [also build test WARNING on geert-m68k/for-next powerpc/next powerpc/fixes s390/features linus/master v6.13-rc6 next-20250110] [cannot apply to geert-m68k/for-linus deller-parisc/for-next jcmvbkbc-xtensa/xtensa-for-next tip/x86/asm] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Andrey-Albershteyn/fs-introduce-getfsxattrat-and-setfsxattrat-syscalls/20250110-014739 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250109174540.893098-1-aalbersh%40kernel.org patch subject: [PATCH] fs: introduce getfsxattrat and setfsxattrat syscalls config: riscv-randconfig-002-20250111 (https://download.01.org/0day-ci/archive/20250112/202501120410.3ZwwYXqY-lkp@intel.com/config) compiler: riscv64-linux-gcc (GCC) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250112/202501120410.3ZwwYXqY-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202501120410.3ZwwYXqY-lkp@intel.com/ All warnings (new ones prefixed by >>): >> <stdin>:1615:2: warning: #warning syscall getfsxattrat not implemented [-Wcpp] >> <stdin>:1618:2: warning: #warning syscall setfsxattrat not implemented [-Wcpp] -- >> <stdin>:1615:2: warning: #warning syscall getfsxattrat not implemented [-Wcpp] >> <stdin>:1618:2: warning: #warning syscall setfsxattrat not implemented [-Wcpp] -- >> <stdin>:1615:2: warning: #warning syscall getfsxattrat not implemented [-Wcpp] >> <stdin>:1618:2: warning: #warning syscall setfsxattrat not implemented [-Wcpp]
Hi Andrey, kernel test robot noticed the following build warnings: [auto build test WARNING on brauner-vfs/vfs.all] [also build test WARNING on geert-m68k/for-next powerpc/next powerpc/fixes s390/features linus/master v6.13-rc6 next-20250110] [cannot apply to geert-m68k/for-linus deller-parisc/for-next jcmvbkbc-xtensa/xtensa-for-next arnd-asm-generic/master tip/x86/asm] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Andrey-Albershteyn/fs-introduce-getfsxattrat-and-setfsxattrat-syscalls/20250110-014739 base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all patch link: https://lore.kernel.org/r/20250109174540.893098-1-aalbersh%40kernel.org patch subject: [PATCH] fs: introduce getfsxattrat and setfsxattrat syscalls config: m68k-randconfig-r122-20250111 (https://download.01.org/0day-ci/archive/20250113/202501131033.KKMmoHBV-lkp@intel.com/config) compiler: m68k-linux-gcc (GCC) 14.2.0 reproduce: (https://download.01.org/0day-ci/archive/20250113/202501131033.KKMmoHBV-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202501131033.KKMmoHBV-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) fs/inode.c:957:24: sparse: sparse: context imbalance in 'inode_lru_isolate' - wrong count at exit fs/inode.c:1058:9: sparse: sparse: context imbalance in 'find_inode' - different lock contexts for basic block fs/inode.c:1099:9: sparse: sparse: context imbalance in 'find_inode_fast' - different lock contexts for basic block fs/inode.c:1829:5: sparse: sparse: context imbalance in 'insert_inode_locked' - wrong count at exit fs/inode.c:1947:20: sparse: sparse: context imbalance in 'iput_final' - unexpected unlock fs/inode.c:1961:6: sparse: sparse: context imbalance in 'iput' - wrong count at exit fs/inode.c:2494:17: sparse: sparse: context imbalance in '__wait_on_freeing_inode' - unexpected unlock >> fs/inode.c:2998:39: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct fsxattr [noderef] __user *ufa @@ got struct fsxattr *fsx @@ fs/inode.c:2998:39: sparse: expected struct fsxattr [noderef] __user *ufa fs/inode.c:2998:39: sparse: got struct fsxattr *fsx fs/inode.c:3032:41: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected struct fsxattr [noderef] __user *ufa @@ got struct fsxattr *fsx @@ fs/inode.c:3032:41: sparse: expected struct fsxattr [noderef] __user *ufa fs/inode.c:3032:41: sparse: got struct fsxattr *fsx vim +2998 fs/inode.c 2959 2960 SYSCALL_DEFINE4(getfsxattrat, int, dfd, const char __user *, filename, 2961 struct fsxattr *, fsx, int, at_flags) 2962 { 2963 struct fd dir; 2964 struct fileattr fa; 2965 struct path filepath; 2966 struct inode *inode; 2967 int error; 2968 2969 if (at_flags) 2970 return -EINVAL; 2971 2972 if (!capable(CAP_FOWNER)) 2973 return -EPERM; 2974 2975 dir = fdget(dfd); 2976 if (!fd_file(dir)) 2977 return -EBADF; 2978 2979 if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { 2980 error = -EBADF; 2981 goto out; 2982 } 2983 2984 error = user_path_at(dfd, filename, at_flags, &filepath); 2985 if (error) 2986 goto out; 2987 2988 inode = filepath.dentry->d_inode; 2989 if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { 2990 error = -EBADF; 2991 goto out_path; 2992 } 2993 2994 error = vfs_fileattr_get(filepath.dentry, &fa); 2995 if (error) 2996 goto out_path; 2997 > 2998 if (copy_fsxattr_to_user(&fa, fsx)) 2999 error = -EFAULT; 3000 3001 out_path: 3002 path_put(&filepath); 3003 out: 3004 fdput(dir); 3005 return error; 3006 } 3007
On Thu 09-01-25 18:45:40, Andrey Albershteyn wrote: > From: Andrey Albershteyn <aalbersh@redhat.com> > > Introduce getfsxattrat and setfsxattrat 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. By having this we can manipulated > inode extended attributes not only on normal files but also on > special ones. This is not possible with FS_IOC_FSSETXATTR ioctl as > opening special files returns VFS special inode instead of > underlying filesystem one. > > This patch adds two new syscalls which allows userspace to set > extended inode attributes on special files by using parent directory > to open FS inode. > > Also, as vfs_fileattr_set() is now will be called on special files > too, let's forbid any other attributes except projid and nextents > (symlink can have an extent). > > CC: linux-api@vger.kernel.org > Signed-off-by: Andrey Albershteyn <aalbersh@redhat.com> Couple of comments below: > @@ -2953,3 +2956,105 @@ umode_t mode_strip_sgid(struct mnt_idmap *idmap, > return mode & ~S_ISGID; > } > EXPORT_SYMBOL(mode_strip_sgid); > + > +SYSCALL_DEFINE4(getfsxattrat, int, dfd, const char __user *, filename, > + struct fsxattr *, fsx, int, at_flags) ^^^ at_flags should be probably unsigned - at least they seem to be for other syscalls. > +{ > + struct fd dir; > + struct fileattr fa; > + struct path filepath; > + struct inode *inode; > + int error; > + > + if (at_flags) > + return -EINVAL; Shouldn't we support basic path resolve flags like AT_SYMLINK_NOFOLLOW or AT_EMPTY_PATH? I didn't put too much thought to this but intuitively I'd say we should follow what path_setxattrat() does. > + > + if (!capable(CAP_FOWNER)) > + return -EPERM; Why? Firstly this does not handle user namespaces at all, secondly it doesn't match the check done during ioctl, and thirdly vfs_fileattr_get() should do all the needed checks? > + > + dir = fdget(dfd); > + if (!fd_file(dir)) > + return -EBADF; > + > + if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { > + error = -EBADF; > + goto out; > + } > + > + error = user_path_at(dfd, filename, at_flags, &filepath); > + if (error) > + goto out; I guess this is OK for now but allowing full flexibility of the "_at" syscall (e.g. like setxattrat() does) would be preferred. Mostly so that userspace programmer doesn't have to read manpage in detail and think whether the particular combination of path arguments is supported by a particular syscall. Admittedly VFS could make this a bit simpler. Currently the boilerplate code that's needed in path_setxattrat() & filename_setxattr() / file_setxattr() is offputting. > + > + inode = filepath.dentry->d_inode; > + if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { > + error = -EBADF; > + goto out_path; > + } What's the motivation for this check? > + > + error = vfs_fileattr_get(filepath.dentry, &fa); > + if (error) > + goto out_path; > + > + if (copy_fsxattr_to_user(&fa, fsx)) > + error = -EFAULT; > + > +out_path: > + path_put(&filepath); > +out: > + fdput(dir); > + return error; > +} > + > +SYSCALL_DEFINE4(setfsxattrat, int, dfd, const char __user *, filename, > + struct fsxattr *, fsx, int, at_flags) > +{ Same comments as for getfsxattrat() apply here as well. > -static int copy_fsxattr_from_user(struct fileattr *fa, > - struct fsxattr __user *ufa) > +int copy_fsxattr_from_user(struct fileattr *fa, struct fsxattr __user *ufa) > { > struct fsxattr xfa; > > @@ -574,6 +573,7 @@ static int copy_fsxattr_from_user(struct fileattr *fa, > > return 0; > } > +EXPORT_SYMBOL(copy_fsxattr_from_user); I guess no need to export this function? The code you call it from cannot be compiled as a module. Honza
On 2025-01-13 12:19:36, Jan Kara wrote: > On Thu 09-01-25 18:45:40, Andrey Albershteyn wrote: > > From: Andrey Albershteyn <aalbersh@redhat.com> > > > > Introduce getfsxattrat and setfsxattrat 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. By having this we can manipulated > > inode extended attributes not only on normal files but also on > > special ones. This is not possible with FS_IOC_FSSETXATTR ioctl as > > opening special files returns VFS special inode instead of > > underlying filesystem one. > > > > This patch adds two new syscalls which allows userspace to set > > extended inode attributes on special files by using parent directory > > to open FS inode. > > > > Also, as vfs_fileattr_set() is now will be called on special files > > too, let's forbid any other attributes except projid and nextents > > (symlink can have an extent). > > > > CC: linux-api@vger.kernel.org > > Signed-off-by: Andrey Albershteyn <aalbersh@redhat.com> > > Couple of comments below: > > > @@ -2953,3 +2956,105 @@ umode_t mode_strip_sgid(struct mnt_idmap *idmap, > > return mode & ~S_ISGID; > > } > > EXPORT_SYMBOL(mode_strip_sgid); > > + > > +SYSCALL_DEFINE4(getfsxattrat, int, dfd, const char __user *, filename, > > + struct fsxattr *, fsx, int, at_flags) > ^^^ at_flags should be probably > unsigned - at least they seem to be for other syscalls. sure > > > +{ > > + struct fd dir; > > + struct fileattr fa; > > + struct path filepath; > > + struct inode *inode; > > + int error; > > + > > + if (at_flags) > > + return -EINVAL; > > Shouldn't we support basic path resolve flags like AT_SYMLINK_NOFOLLOW or > AT_EMPTY_PATH? I didn't put too much thought to this but intuitively I'd say > we should follow what path_setxattrat() does. Hmm, yeah, you are right these two can be passed. I thought about setting AT_SYMLINK_NOFOLLOW by default (which is also missing here), but adding allowing passing these seems to be fine. > > > + > > + if (!capable(CAP_FOWNER)) > > + return -EPERM; > > Why? Firstly this does not handle user namespaces at all, secondly it > doesn't match the check done during ioctl, and thirdly vfs_fileattr_get() > should do all the needed checks? Sorry, miss-understood how this works, I will remove this from both get/set. get*() doesn't need it and set*() checks capabilities in vfs_fileattr_set(). Thanks! > > > + > > + dir = fdget(dfd); > > + if (!fd_file(dir)) > > + return -EBADF; > > + > > + if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { > > + error = -EBADF; > > + goto out; > > + } > > + > > + error = user_path_at(dfd, filename, at_flags, &filepath); > > + if (error) > > + goto out; > > I guess this is OK for now but allowing full flexibility of the "_at" > syscall (e.g. like setxattrat() does) would be preferred. Mostly so that > userspace programmer doesn't have to read manpage in detail and think > whether the particular combination of path arguments is supported by a > particular syscall. Admittedly VFS could make this a bit simpler. Currently > the boilerplate code that's needed in path_setxattrat() & > filename_setxattr() / file_setxattr() is offputting. > > > + > > + inode = filepath.dentry->d_inode; > > + if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { > > + error = -EBADF; > > + goto out_path; > > + } > > What's the motivation for this check? This was one of the comments on the ioctl() patch, that it doesn't make much sense to allow ioctl() to be called over different filesystems. But for syscall this is probably make less sense to restrict it like that. I will drop it. > > > + > > + error = vfs_fileattr_get(filepath.dentry, &fa); > > + if (error) > > + goto out_path; > > + > > + if (copy_fsxattr_to_user(&fa, fsx)) > > + error = -EFAULT; > > + > > +out_path: > > + path_put(&filepath); > > +out: > > + fdput(dir); > > + return error; > > +} > > + > > +SYSCALL_DEFINE4(setfsxattrat, int, dfd, const char __user *, filename, > > + struct fsxattr *, fsx, int, at_flags) > > +{ > > Same comments as for getfsxattrat() apply here as well. > > > -static int copy_fsxattr_from_user(struct fileattr *fa, > > - struct fsxattr __user *ufa) > > +int copy_fsxattr_from_user(struct fileattr *fa, struct fsxattr __user *ufa) > > { > > struct fsxattr xfa; > > > > @@ -574,6 +573,7 @@ static int copy_fsxattr_from_user(struct fileattr *fa, > > > > return 0; > > } > > +EXPORT_SYMBOL(copy_fsxattr_from_user); > > I guess no need to export this function? The code you call it from cannot > be compiled as a module. Yes, that's true, I added this because copy_fsxattr_to_user() also is exported (same as many other functions). I will drop this.
On Thu, Jan 09, 2025 at 06:45:40PM +0100, Andrey Albershteyn wrote: > From: Andrey Albershteyn <aalbersh@redhat.com> > > Introduce getfsxattrat and setfsxattrat 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. By having this we can manipulated > inode extended attributes not only on normal files but also on > special ones. This is not possible with FS_IOC_FSSETXATTR ioctl as > opening special files returns VFS special inode instead of > underlying filesystem one. > > This patch adds two new syscalls which allows userspace to set > extended inode attributes on special files by using parent directory > to open FS inode. > > Also, as vfs_fileattr_set() is now will be called on special files > too, let's forbid any other attributes except projid and nextents > (symlink can have an extent). > > CC: linux-api@vger.kernel.org > Signed-off-by: Andrey Albershteyn <aalbersh@redhat.com> > --- > > Notes: > Previous discussion: > https://lore.kernel.org/linux-xfs/20240520164624.665269-2-aalbersh@redhat.com/ > > XFS has project quotas which could be attached to a directory. All > new inodes in these directories inherit project ID set on parent > directory. > > The project is created from userspace by opening and calling > FS_IOC_FSSETXATTR on each inode. This is not possible for special > files such as FIFO, SOCK, BLK etc. Therefore, some inodes are left > with empty project ID. Those inodes then are not shown in the quota > accounting but still exist in the directory. Moreover, in the case > when special files are created in the directory with already > existing project quota, these inode inherit extended attributes. > This than leaves them with these attributes without the possibility > to clear them out. This, in turn, prevents userspace from > re-creating quota project on these existing files. > > arch/alpha/kernel/syscalls/syscall.tbl | 2 + > arch/m68k/kernel/syscalls/syscall.tbl | 2 + > arch/microblaze/kernel/syscalls/syscall.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/inode.c | 105 ++++++++++++++++++++ > fs/ioctl.c | 17 +++- > include/linux/fileattr.h | 1 + > include/linux/syscalls.h | 4 + > include/uapi/asm-generic/unistd.h | 8 +- > 16 files changed, 154 insertions(+), 3 deletions(-) > > diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl > index c59d53d6d3f3..4b9e687494c1 100644 > --- a/arch/alpha/kernel/syscalls/syscall.tbl > +++ b/arch/alpha/kernel/syscalls/syscall.tbl > @@ -506,3 +506,5 @@ > 574 common getxattrat sys_getxattrat > 575 common listxattrat sys_listxattrat > 576 common removexattrat sys_removexattrat > +577 common getfsxattrat sys_getfsxattrat > +578 common setfsxattrat sys_setfsxattrat > diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl > index f5ed71f1910d..159476387f39 100644 > --- a/arch/m68k/kernel/syscalls/syscall.tbl > +++ b/arch/m68k/kernel/syscalls/syscall.tbl > @@ -466,3 +466,5 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl > index 680f568b77f2..a6d59ee740b5 100644 > --- a/arch/microblaze/kernel/syscalls/syscall.tbl > +++ b/arch/microblaze/kernel/syscalls/syscall.tbl > @@ -472,3 +472,5 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl > index d9fc94c86965..b3578fac43d6 100644 > --- a/arch/parisc/kernel/syscalls/syscall.tbl > +++ b/arch/parisc/kernel/syscalls/syscall.tbl > @@ -465,3 +465,5 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl > index d8b4ab78bef0..808045d82c94 100644 > --- a/arch/powerpc/kernel/syscalls/syscall.tbl > +++ b/arch/powerpc/kernel/syscalls/syscall.tbl > @@ -557,3 +557,5 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl > index e9115b4d8b63..78dfc2c184d4 100644 > --- a/arch/s390/kernel/syscalls/syscall.tbl > +++ b/arch/s390/kernel/syscalls/syscall.tbl > @@ -469,3 +469,5 @@ > 464 common getxattrat sys_getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat sys_setfsxattrat > diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl > index c8cad33bf250..d5a5c8339f0e 100644 > --- a/arch/sh/kernel/syscalls/syscall.tbl > +++ b/arch/sh/kernel/syscalls/syscall.tbl > @@ -470,3 +470,5 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl > index 727f99d333b3..817dcd8603bc 100644 > --- a/arch/sparc/kernel/syscalls/syscall.tbl > +++ b/arch/sparc/kernel/syscalls/syscall.tbl > @@ -512,3 +512,5 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl > index 4d0fb2fba7e2..b4842c027c5d 100644 > --- a/arch/x86/entry/syscalls/syscall_32.tbl > +++ b/arch/x86/entry/syscalls/syscall_32.tbl > @@ -472,3 +472,5 @@ > 464 i386 getxattrat sys_getxattrat > 465 i386 listxattrat sys_listxattrat > 466 i386 removexattrat sys_removexattrat > +467 i386 getfsxattrat sys_getfsxattrat > +468 i386 setfsxattrat sys_setfsxattrat > diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl > index 5eb708bff1c7..b6f0a7236aae 100644 > --- a/arch/x86/entry/syscalls/syscall_64.tbl > +++ b/arch/x86/entry/syscalls/syscall_64.tbl > @@ -390,6 +390,8 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > > # > # 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 37effc1b134e..425d56be337d 100644 > --- a/arch/xtensa/kernel/syscalls/syscall.tbl > +++ b/arch/xtensa/kernel/syscalls/syscall.tbl > @@ -437,3 +437,5 @@ > 464 common getxattrat sys_getxattrat > 465 common listxattrat sys_listxattrat > 466 common removexattrat sys_removexattrat > +467 common getfsxattrat sys_getfsxattrat > +468 common setfsxattrat sys_setfsxattrat > diff --git a/fs/inode.c b/fs/inode.c > index 6b4c77268fc0..fc8939c6c8a7 100644 > --- a/fs/inode.c > +++ b/fs/inode.c > @@ -23,6 +23,9 @@ > #include <linux/rw_hint.h> > #include <linux/seq_file.h> > #include <linux/debugfs.h> > +#include <linux/syscalls.h> > +#include <linux/fileattr.h> > +#include <linux/namei.h> > #include <trace/events/writeback.h> > #define CREATE_TRACE_POINTS > #include <trace/events/timestamp.h> > @@ -2953,3 +2956,105 @@ umode_t mode_strip_sgid(struct mnt_idmap *idmap, > return mode & ~S_ISGID; > } > EXPORT_SYMBOL(mode_strip_sgid); > + > +SYSCALL_DEFINE4(getfsxattrat, int, dfd, const char __user *, filename, > + struct fsxattr *, fsx, int, at_flags) > +{ > + struct fd dir; > + struct fileattr fa; > + struct path filepath; > + struct inode *inode; > + int error; > + > + if (at_flags) > + return -EINVAL; > + > + if (!capable(CAP_FOWNER)) > + return -EPERM; > + > + dir = fdget(dfd); > + if (!fd_file(dir)) > + return -EBADF; > + > + if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { > + error = -EBADF; > + goto out; > + } > + > + error = user_path_at(dfd, filename, at_flags, &filepath); Same comments as Jan, but I wanted to point out that the third argument to user_path_at() is LOOKUP_*, not AT_*. Right now you don't allow any AT_* flags, but that's something to fix before the next revision. --D > + if (error) > + goto out; > + > + inode = filepath.dentry->d_inode; > + if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { > + error = -EBADF; > + goto out_path; > + } > + > + error = vfs_fileattr_get(filepath.dentry, &fa); > + if (error) > + goto out_path; > + > + if (copy_fsxattr_to_user(&fa, fsx)) > + error = -EFAULT; > + > +out_path: > + path_put(&filepath); > +out: > + fdput(dir); > + return error; > +} > + > +SYSCALL_DEFINE4(setfsxattrat, int, dfd, const char __user *, filename, > + struct fsxattr *, fsx, int, at_flags) > +{ > + struct fd dir; > + struct fileattr fa; > + struct inode *inode; > + struct path filepath; > + int error; > + > + if (at_flags) > + return -EINVAL; > + > + if (!capable(CAP_FOWNER)) > + return -EPERM; > + > + dir = fdget(dfd); > + if (!fd_file(dir)) > + return -EBADF; > + > + if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { > + error = -EBADF; > + goto out; > + } > + > + if (copy_fsxattr_from_user(&fa, fsx)) { > + error = -EFAULT; > + goto out; > + } > + > + error = user_path_at(dfd, filename, at_flags, &filepath); > + if (error) > + goto out; > + > + inode = filepath.dentry->d_inode; > + if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { > + error = -EBADF; > + goto out_path; > + } > + > + error = mnt_want_write(filepath.mnt); > + if (error) > + goto out_path; > + > + error = vfs_fileattr_set(file_mnt_idmap(fd_file(dir)), filepath.dentry, > + &fa); > + mnt_drop_write(filepath.mnt); > + > +out_path: > + path_put(&filepath); > +out: > + fdput(dir); > + return error; > +} > diff --git a/fs/ioctl.c b/fs/ioctl.c > index 638a36be31c1..df14f1868165 100644 > --- a/fs/ioctl.c > +++ b/fs/ioctl.c > @@ -558,8 +558,7 @@ int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa) > } > EXPORT_SYMBOL(copy_fsxattr_to_user); > > -static int copy_fsxattr_from_user(struct fileattr *fa, > - struct fsxattr __user *ufa) > +int copy_fsxattr_from_user(struct fileattr *fa, struct fsxattr __user *ufa) > { > struct fsxattr xfa; > > @@ -574,6 +573,7 @@ static int copy_fsxattr_from_user(struct fileattr *fa, > > return 0; > } > +EXPORT_SYMBOL(copy_fsxattr_from_user); > > /* > * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject > @@ -646,6 +646,19 @@ static int fileattr_set_prepare(struct inode *inode, > if (fa->fsx_cowextsize == 0) > fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; > > + /* > + * The only use case for special files is to set project ID, forbid any > + * other attributes > + */ > + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { > + if (fa->fsx_xflags & ~FS_XFLAG_PROJINHERIT) > + return -EINVAL; > + if (!S_ISLNK(inode->i_mode) && fa->fsx_nextents) > + return -EINVAL; > + if (fa->fsx_extsize || fa->fsx_cowextsize) > + return -EINVAL; > + } > + > return 0; > } > > diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h > index 47c05a9851d0..8598e94b530b 100644 > --- a/include/linux/fileattr.h > +++ b/include/linux/fileattr.h > @@ -34,6 +34,7 @@ struct fileattr { > }; > > int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa); > +int copy_fsxattr_from_user(struct fileattr *fa, struct fsxattr __user *ufa); > > void fileattr_fill_xflags(struct fileattr *fa, u32 xflags); > void fileattr_fill_flags(struct fileattr *fa, u32 flags); > diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h > index c6333204d451..a983023d21ab 100644 > --- a/include/linux/syscalls.h > +++ b/include/linux/syscalls.h > @@ -371,6 +371,10 @@ 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_getfsxattrat(int dfd, const char __user *filename, > + struct fsxattr *fsx, int at_flags); > +asmlinkage long sys_setfsxattrat(int dfd, const char __user *filename, > + struct fsxattr *fsx, 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 88dc393c2bca..50be2e1007bc 100644 > --- a/include/uapi/asm-generic/unistd.h > +++ b/include/uapi/asm-generic/unistd.h > @@ -850,8 +850,14 @@ __SYSCALL(__NR_listxattrat, sys_listxattrat) > #define __NR_removexattrat 466 > __SYSCALL(__NR_removexattrat, sys_removexattrat) > > +/* fs/inode.c */ > +#define __NR_getfsxattrat 467 > +__SYSCALL(__NR_getfsxattrat, sys_getfsxattrat) > +#define __NR_setfsxattrat 468 > +__SYSCALL(__NR_setfsxattrat, sys_setfsxattrat) > + > #undef __NR_syscalls > -#define __NR_syscalls 467 > +#define __NR_syscalls 469 > > /* > * 32 bit systems traditionally used different > -- > 2.47.0 > >
diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl index c59d53d6d3f3..4b9e687494c1 100644 --- a/arch/alpha/kernel/syscalls/syscall.tbl +++ b/arch/alpha/kernel/syscalls/syscall.tbl @@ -506,3 +506,5 @@ 574 common getxattrat sys_getxattrat 575 common listxattrat sys_listxattrat 576 common removexattrat sys_removexattrat +577 common getfsxattrat sys_getfsxattrat +578 common setfsxattrat sys_setfsxattrat diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl index f5ed71f1910d..159476387f39 100644 --- a/arch/m68k/kernel/syscalls/syscall.tbl +++ b/arch/m68k/kernel/syscalls/syscall.tbl @@ -466,3 +466,5 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl index 680f568b77f2..a6d59ee740b5 100644 --- a/arch/microblaze/kernel/syscalls/syscall.tbl +++ b/arch/microblaze/kernel/syscalls/syscall.tbl @@ -472,3 +472,5 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl index d9fc94c86965..b3578fac43d6 100644 --- a/arch/parisc/kernel/syscalls/syscall.tbl +++ b/arch/parisc/kernel/syscalls/syscall.tbl @@ -465,3 +465,5 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl index d8b4ab78bef0..808045d82c94 100644 --- a/arch/powerpc/kernel/syscalls/syscall.tbl +++ b/arch/powerpc/kernel/syscalls/syscall.tbl @@ -557,3 +557,5 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl index e9115b4d8b63..78dfc2c184d4 100644 --- a/arch/s390/kernel/syscalls/syscall.tbl +++ b/arch/s390/kernel/syscalls/syscall.tbl @@ -469,3 +469,5 @@ 464 common getxattrat sys_getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat sys_setfsxattrat diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl index c8cad33bf250..d5a5c8339f0e 100644 --- a/arch/sh/kernel/syscalls/syscall.tbl +++ b/arch/sh/kernel/syscalls/syscall.tbl @@ -470,3 +470,5 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl index 727f99d333b3..817dcd8603bc 100644 --- a/arch/sparc/kernel/syscalls/syscall.tbl +++ b/arch/sparc/kernel/syscalls/syscall.tbl @@ -512,3 +512,5 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 4d0fb2fba7e2..b4842c027c5d 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -472,3 +472,5 @@ 464 i386 getxattrat sys_getxattrat 465 i386 listxattrat sys_listxattrat 466 i386 removexattrat sys_removexattrat +467 i386 getfsxattrat sys_getfsxattrat +468 i386 setfsxattrat sys_setfsxattrat diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 5eb708bff1c7..b6f0a7236aae 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -390,6 +390,8 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat # # 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 37effc1b134e..425d56be337d 100644 --- a/arch/xtensa/kernel/syscalls/syscall.tbl +++ b/arch/xtensa/kernel/syscalls/syscall.tbl @@ -437,3 +437,5 @@ 464 common getxattrat sys_getxattrat 465 common listxattrat sys_listxattrat 466 common removexattrat sys_removexattrat +467 common getfsxattrat sys_getfsxattrat +468 common setfsxattrat sys_setfsxattrat diff --git a/fs/inode.c b/fs/inode.c index 6b4c77268fc0..fc8939c6c8a7 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -23,6 +23,9 @@ #include <linux/rw_hint.h> #include <linux/seq_file.h> #include <linux/debugfs.h> +#include <linux/syscalls.h> +#include <linux/fileattr.h> +#include <linux/namei.h> #include <trace/events/writeback.h> #define CREATE_TRACE_POINTS #include <trace/events/timestamp.h> @@ -2953,3 +2956,105 @@ umode_t mode_strip_sgid(struct mnt_idmap *idmap, return mode & ~S_ISGID; } EXPORT_SYMBOL(mode_strip_sgid); + +SYSCALL_DEFINE4(getfsxattrat, int, dfd, const char __user *, filename, + struct fsxattr *, fsx, int, at_flags) +{ + struct fd dir; + struct fileattr fa; + struct path filepath; + struct inode *inode; + int error; + + if (at_flags) + return -EINVAL; + + if (!capable(CAP_FOWNER)) + return -EPERM; + + dir = fdget(dfd); + if (!fd_file(dir)) + return -EBADF; + + if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { + error = -EBADF; + goto out; + } + + error = user_path_at(dfd, filename, at_flags, &filepath); + if (error) + goto out; + + inode = filepath.dentry->d_inode; + if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { + error = -EBADF; + goto out_path; + } + + error = vfs_fileattr_get(filepath.dentry, &fa); + if (error) + goto out_path; + + if (copy_fsxattr_to_user(&fa, fsx)) + error = -EFAULT; + +out_path: + path_put(&filepath); +out: + fdput(dir); + return error; +} + +SYSCALL_DEFINE4(setfsxattrat, int, dfd, const char __user *, filename, + struct fsxattr *, fsx, int, at_flags) +{ + struct fd dir; + struct fileattr fa; + struct inode *inode; + struct path filepath; + int error; + + if (at_flags) + return -EINVAL; + + if (!capable(CAP_FOWNER)) + return -EPERM; + + dir = fdget(dfd); + if (!fd_file(dir)) + return -EBADF; + + if (!S_ISDIR(file_inode(fd_file(dir))->i_mode)) { + error = -EBADF; + goto out; + } + + if (copy_fsxattr_from_user(&fa, fsx)) { + error = -EFAULT; + goto out; + } + + error = user_path_at(dfd, filename, at_flags, &filepath); + if (error) + goto out; + + inode = filepath.dentry->d_inode; + if (file_inode(fd_file(dir))->i_sb->s_magic != inode->i_sb->s_magic) { + error = -EBADF; + goto out_path; + } + + error = mnt_want_write(filepath.mnt); + if (error) + goto out_path; + + error = vfs_fileattr_set(file_mnt_idmap(fd_file(dir)), filepath.dentry, + &fa); + mnt_drop_write(filepath.mnt); + +out_path: + path_put(&filepath); +out: + fdput(dir); + return error; +} diff --git a/fs/ioctl.c b/fs/ioctl.c index 638a36be31c1..df14f1868165 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -558,8 +558,7 @@ int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa) } EXPORT_SYMBOL(copy_fsxattr_to_user); -static int copy_fsxattr_from_user(struct fileattr *fa, - struct fsxattr __user *ufa) +int copy_fsxattr_from_user(struct fileattr *fa, struct fsxattr __user *ufa) { struct fsxattr xfa; @@ -574,6 +573,7 @@ static int copy_fsxattr_from_user(struct fileattr *fa, return 0; } +EXPORT_SYMBOL(copy_fsxattr_from_user); /* * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject @@ -646,6 +646,19 @@ static int fileattr_set_prepare(struct inode *inode, if (fa->fsx_cowextsize == 0) fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; + /* + * The only use case for special files is to set project ID, forbid any + * other attributes + */ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { + if (fa->fsx_xflags & ~FS_XFLAG_PROJINHERIT) + return -EINVAL; + if (!S_ISLNK(inode->i_mode) && fa->fsx_nextents) + return -EINVAL; + if (fa->fsx_extsize || fa->fsx_cowextsize) + return -EINVAL; + } + return 0; } diff --git a/include/linux/fileattr.h b/include/linux/fileattr.h index 47c05a9851d0..8598e94b530b 100644 --- a/include/linux/fileattr.h +++ b/include/linux/fileattr.h @@ -34,6 +34,7 @@ struct fileattr { }; int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa); +int copy_fsxattr_from_user(struct fileattr *fa, struct fsxattr __user *ufa); void fileattr_fill_xflags(struct fileattr *fa, u32 xflags); void fileattr_fill_flags(struct fileattr *fa, u32 flags); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index c6333204d451..a983023d21ab 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -371,6 +371,10 @@ 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_getfsxattrat(int dfd, const char __user *filename, + struct fsxattr *fsx, int at_flags); +asmlinkage long sys_setfsxattrat(int dfd, const char __user *filename, + struct fsxattr *fsx, 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 88dc393c2bca..50be2e1007bc 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -850,8 +850,14 @@ __SYSCALL(__NR_listxattrat, sys_listxattrat) #define __NR_removexattrat 466 __SYSCALL(__NR_removexattrat, sys_removexattrat) +/* fs/inode.c */ +#define __NR_getfsxattrat 467 +__SYSCALL(__NR_getfsxattrat, sys_getfsxattrat) +#define __NR_setfsxattrat 468 +__SYSCALL(__NR_setfsxattrat, sys_setfsxattrat) + #undef __NR_syscalls -#define __NR_syscalls 467 +#define __NR_syscalls 469 /* * 32 bit systems traditionally used different