Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'vfs-6.17-rc1.fileattr' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull fileattr updates from Christian Brauner:
"This introduces the new file_getattr() and file_setattr() system calls
after lengthy discussions.

Both system calls serve as successors and extensible companions to
the FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR system calls which have
started to show their age in addition to being named in a way that
makes it easy to conflate them with extended attribute related
operations.

These syscalls allow userspace to set filesystem inode attributes on
special files. One of the usage examples is the XFS quota projects.

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. This is not critical but
in the case when special files are created in the directory with
already existing project quota, these new inodes inherit extended
attributes. This creates a mix of special files with and without
attributes. Moreover, special files with attributes don't have a
possibility to become clear or change the attributes. This, in turn,
prevents userspace from re-creating quota project on these existing
files.

In addition, these new system calls allow the implementation of
additional attributes that we couldn't or didn't want to fit into the
legacy ioctls anymore"

* tag 'vfs-6.17-rc1.fileattr' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
fs: tighten a sanity check in file_attr_to_fileattr()
tree-wide: s/struct fileattr/struct file_kattr/g
fs: introduce file_getattr and file_setattr syscalls
fs: prepare for extending file_get/setattr()
fs: make vfs_fileattr_[get|set] return -EOPNOTSUPP
selinux: implement inode_file_[g|s]etattr hooks
lsm: introduce new hooks for setting/getting inode fsxattr
fs: split fileattr related helpers into separate file

+752 -410
+2 -2
Documentation/filesystems/locking.rst
··· 87 87 int (*tmpfile) (struct mnt_idmap *, struct inode *, 88 88 struct file *, umode_t); 89 89 int (*fileattr_set)(struct mnt_idmap *idmap, 90 - struct dentry *dentry, struct fileattr *fa); 91 - int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); 90 + struct dentry *dentry, struct file_kattr *fa); 91 + int (*fileattr_get)(struct dentry *dentry, struct file_kattr *fa); 92 92 struct posix_acl * (*get_acl)(struct mnt_idmap *, struct dentry *, int); 93 93 struct offset_ctx *(*get_offset_ctx)(struct inode *inode); 94 94
+2 -2
Documentation/filesystems/vfs.rst
··· 515 515 struct posix_acl * (*get_acl)(struct mnt_idmap *, struct dentry *, int); 516 516 int (*set_acl)(struct mnt_idmap *, struct dentry *, struct posix_acl *, int); 517 517 int (*fileattr_set)(struct mnt_idmap *idmap, 518 - struct dentry *dentry, struct fileattr *fa); 519 - int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); 518 + struct dentry *dentry, struct file_kattr *fa); 519 + int (*fileattr_get)(struct dentry *dentry, struct file_kattr *fa); 520 520 struct offset_ctx *(*get_offset_ctx)(struct inode *inode); 521 521 }; 522 522
+2
arch/alpha/kernel/syscalls/syscall.tbl
··· 507 507 575 common listxattrat sys_listxattrat 508 508 576 common removexattrat sys_removexattrat 509 509 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
+2
arch/arm/tools/syscall.tbl
··· 482 482 465 common listxattrat sys_listxattrat 483 483 466 common removexattrat sys_removexattrat 484 484 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
+2
arch/arm64/tools/syscall_32.tbl
··· 479 479 465 common listxattrat sys_listxattrat 480 480 466 common removexattrat sys_removexattrat 481 481 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
+2
arch/m68k/kernel/syscalls/syscall.tbl
··· 467 467 465 common listxattrat sys_listxattrat 468 468 466 common removexattrat sys_removexattrat 469 469 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
+2
arch/microblaze/kernel/syscalls/syscall.tbl
··· 473 473 465 common listxattrat sys_listxattrat 474 474 466 common removexattrat sys_removexattrat 475 475 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
+2
arch/mips/kernel/syscalls/syscall_n32.tbl
··· 406 406 465 n32 listxattrat sys_listxattrat 407 407 466 n32 removexattrat sys_removexattrat 408 408 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
+2
arch/mips/kernel/syscalls/syscall_n64.tbl
··· 382 382 465 n64 listxattrat sys_listxattrat 383 383 466 n64 removexattrat sys_removexattrat 384 384 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
+2
arch/mips/kernel/syscalls/syscall_o32.tbl
··· 455 455 465 o32 listxattrat sys_listxattrat 456 456 466 o32 removexattrat sys_removexattrat 457 457 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
+2
arch/parisc/kernel/syscalls/syscall.tbl
··· 466 466 465 common listxattrat sys_listxattrat 467 467 466 common removexattrat sys_removexattrat 468 468 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
+2
arch/powerpc/kernel/syscalls/syscall.tbl
··· 558 558 465 common listxattrat sys_listxattrat 559 559 466 common removexattrat sys_removexattrat 560 560 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
+2
arch/s390/kernel/syscalls/syscall.tbl
··· 470 470 465 common listxattrat sys_listxattrat sys_listxattrat 471 471 466 common removexattrat sys_removexattrat sys_removexattrat 472 472 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
+2
arch/sh/kernel/syscalls/syscall.tbl
··· 471 471 465 common listxattrat sys_listxattrat 472 472 466 common removexattrat sys_removexattrat 473 473 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
+2
arch/sparc/kernel/syscalls/syscall.tbl
··· 513 513 465 common listxattrat sys_listxattrat 514 514 466 common removexattrat sys_removexattrat 515 515 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
+2
arch/x86/entry/syscalls/syscall_32.tbl
··· 473 473 465 i386 listxattrat sys_listxattrat 474 474 466 i386 removexattrat sys_removexattrat 475 475 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
+2
arch/x86/entry/syscalls/syscall_64.tbl
··· 391 391 465 common listxattrat sys_listxattrat 392 392 466 common removexattrat sys_removexattrat 393 393 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 394 396 395 397 # 396 398 # Due to a historical design error, certain syscalls are numbered differently
+2
arch/xtensa/kernel/syscalls/syscall.tbl
··· 438 438 465 common listxattrat sys_listxattrat 439 439 466 common removexattrat sys_removexattrat 440 440 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
+2 -1
fs/Makefile
··· 15 15 pnode.o splice.o sync.o utimes.o d_path.o \ 16 16 stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \ 17 17 fs_types.o fs_context.o fs_parser.o fsopen.o init.o \ 18 - kernel_read_file.o mnt_idmapping.o remap_range.o pidfs.o 18 + kernel_read_file.o mnt_idmapping.o remap_range.o pidfs.o \ 19 + file_attr.o 19 20 20 21 obj-$(CONFIG_BUFFER_HEAD) += buffer.o mpage.o 21 22 obj-$(CONFIG_PROC_FS) += proc_namespace.o
+2 -2
fs/bcachefs/fs.c
··· 1617 1617 }; 1618 1618 1619 1619 static int bch2_fileattr_get(struct dentry *dentry, 1620 - struct fileattr *fa) 1620 + struct file_kattr *fa) 1621 1621 { 1622 1622 struct bch_inode_info *inode = to_bch_ei(d_inode(dentry)); 1623 1623 struct bch_fs *c = inode->v.i_sb->s_fs_info; ··· 1680 1680 1681 1681 static int bch2_fileattr_set(struct mnt_idmap *idmap, 1682 1682 struct dentry *dentry, 1683 - struct fileattr *fa) 1683 + struct file_kattr *fa) 1684 1684 { 1685 1685 struct bch_inode_info *inode = to_bch_ei(d_inode(dentry)); 1686 1686 struct bch_fs *c = inode->v.i_sb->s_fs_info;
+2 -2
fs/btrfs/ioctl.c
··· 245 245 * Set flags/xflags from the internal inode flags. The remaining items of 246 246 * fsxattr are zeroed. 247 247 */ 248 - int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 248 + int btrfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 249 249 { 250 250 const struct btrfs_inode *inode = BTRFS_I(d_inode(dentry)); 251 251 ··· 254 254 } 255 255 256 256 int btrfs_fileattr_set(struct mnt_idmap *idmap, 257 - struct dentry *dentry, struct fileattr *fa) 257 + struct dentry *dentry, struct file_kattr *fa) 258 258 { 259 259 struct btrfs_inode *inode = BTRFS_I(d_inode(dentry)); 260 260 struct btrfs_root *root = inode->root;
+3 -3
fs/btrfs/ioctl.h
··· 8 8 struct file; 9 9 struct dentry; 10 10 struct mnt_idmap; 11 - struct fileattr; 11 + struct file_kattr; 12 12 struct io_uring_cmd; 13 13 struct btrfs_inode; 14 14 struct btrfs_fs_info; ··· 16 16 17 17 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 18 18 long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 19 - int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa); 19 + int btrfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 20 20 int btrfs_fileattr_set(struct mnt_idmap *idmap, 21 - struct dentry *dentry, struct fileattr *fa); 21 + struct dentry *dentry, struct file_kattr *fa); 22 22 int btrfs_ioctl_get_supported_features(void __user *arg); 23 23 void btrfs_sync_inode_flags_to_i_flags(struct btrfs_inode *inode); 24 24 void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
+2 -2
fs/ecryptfs/inode.c
··· 1124 1124 return rc; 1125 1125 } 1126 1126 1127 - static int ecryptfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 1127 + static int ecryptfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 1128 1128 { 1129 1129 return vfs_fileattr_get(ecryptfs_dentry_to_lower(dentry), fa); 1130 1130 } 1131 1131 1132 1132 static int ecryptfs_fileattr_set(struct mnt_idmap *idmap, 1133 - struct dentry *dentry, struct fileattr *fa) 1133 + struct dentry *dentry, struct file_kattr *fa) 1134 1134 { 1135 1135 struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); 1136 1136 int rc;
+2 -2
fs/efivarfs/inode.c
··· 138 138 }; 139 139 140 140 static int 141 - efivarfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 141 + efivarfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 142 142 { 143 143 unsigned int i_flags; 144 144 unsigned int flags = 0; ··· 154 154 155 155 static int 156 156 efivarfs_fileattr_set(struct mnt_idmap *idmap, 157 - struct dentry *dentry, struct fileattr *fa) 157 + struct dentry *dentry, struct file_kattr *fa) 158 158 { 159 159 unsigned int i_flags = 0; 160 160
+2 -2
fs/ext2/ext2.h
··· 750 750 u64 start, u64 len); 751 751 752 752 /* ioctl.c */ 753 - extern int ext2_fileattr_get(struct dentry *dentry, struct fileattr *fa); 753 + extern int ext2_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 754 754 extern int ext2_fileattr_set(struct mnt_idmap *idmap, 755 - struct dentry *dentry, struct fileattr *fa); 755 + struct dentry *dentry, struct file_kattr *fa); 756 756 extern long ext2_ioctl(struct file *, unsigned int, unsigned long); 757 757 extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long); 758 758
+2 -2
fs/ext2/ioctl.c
··· 18 18 #include <linux/uaccess.h> 19 19 #include <linux/fileattr.h> 20 20 21 - int ext2_fileattr_get(struct dentry *dentry, struct fileattr *fa) 21 + int ext2_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 22 22 { 23 23 struct ext2_inode_info *ei = EXT2_I(d_inode(dentry)); 24 24 ··· 28 28 } 29 29 30 30 int ext2_fileattr_set(struct mnt_idmap *idmap, 31 - struct dentry *dentry, struct fileattr *fa) 31 + struct dentry *dentry, struct file_kattr *fa) 32 32 { 33 33 struct inode *inode = d_inode(dentry); 34 34 struct ext2_inode_info *ei = EXT2_I(inode);
+2 -2
fs/ext4/ext4.h
··· 3103 3103 extern long ext4_ioctl(struct file *, unsigned int, unsigned long); 3104 3104 extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); 3105 3105 int ext4_fileattr_set(struct mnt_idmap *idmap, 3106 - struct dentry *dentry, struct fileattr *fa); 3107 - int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa); 3106 + struct dentry *dentry, struct file_kattr *fa); 3107 + int ext4_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 3108 3108 extern void ext4_reset_inode_seed(struct inode *inode); 3109 3109 int ext4_update_overhead(struct super_block *sb, bool force); 3110 3110 int ext4_force_shutdown(struct super_block *sb, u32 flags);
+2 -2
fs/ext4/ioctl.c
··· 980 980 return err; 981 981 } 982 982 983 - int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa) 983 + int ext4_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 984 984 { 985 985 struct inode *inode = d_inode(dentry); 986 986 struct ext4_inode_info *ei = EXT4_I(inode); ··· 997 997 } 998 998 999 999 int ext4_fileattr_set(struct mnt_idmap *idmap, 1000 - struct dentry *dentry, struct fileattr *fa) 1000 + struct dentry *dentry, struct file_kattr *fa) 1001 1001 { 1002 1002 struct inode *inode = d_inode(dentry); 1003 1003 u32 flags = fa->flags;
+2 -2
fs/f2fs/f2fs.h
··· 3615 3615 int f2fs_do_shutdown(struct f2fs_sb_info *sbi, unsigned int flag, 3616 3616 bool readonly, bool need_lock); 3617 3617 int f2fs_precache_extents(struct inode *inode); 3618 - int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa); 3618 + int f2fs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 3619 3619 int f2fs_fileattr_set(struct mnt_idmap *idmap, 3620 - struct dentry *dentry, struct fileattr *fa); 3620 + struct dentry *dentry, struct file_kattr *fa); 3621 3621 long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 3622 3622 long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 3623 3623 int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid);
+2 -2
fs/f2fs/file.c
··· 3391 3391 } 3392 3392 #endif 3393 3393 3394 - int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 3394 + int f2fs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 3395 3395 { 3396 3396 struct inode *inode = d_inode(dentry); 3397 3397 struct f2fs_inode_info *fi = F2FS_I(inode); ··· 3415 3415 } 3416 3416 3417 3417 int f2fs_fileattr_set(struct mnt_idmap *idmap, 3418 - struct dentry *dentry, struct fileattr *fa) 3418 + struct dentry *dentry, struct file_kattr *fa) 3419 3419 { 3420 3420 struct inode *inode = d_inode(dentry); 3421 3421 u32 fsflags = fa->flags, mask = F2FS_SETTABLE_FS_FL;
+498
fs/file_attr.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/fs.h> 3 + #include <linux/security.h> 4 + #include <linux/fscrypt.h> 5 + #include <linux/fileattr.h> 6 + #include <linux/export.h> 7 + #include <linux/syscalls.h> 8 + #include <linux/namei.h> 9 + 10 + #include "internal.h" 11 + 12 + /** 13 + * fileattr_fill_xflags - initialize fileattr with xflags 14 + * @fa: fileattr pointer 15 + * @xflags: FS_XFLAG_* flags 16 + * 17 + * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All 18 + * other fields are zeroed. 19 + */ 20 + void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags) 21 + { 22 + memset(fa, 0, sizeof(*fa)); 23 + fa->fsx_valid = true; 24 + fa->fsx_xflags = xflags; 25 + if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE) 26 + fa->flags |= FS_IMMUTABLE_FL; 27 + if (fa->fsx_xflags & FS_XFLAG_APPEND) 28 + fa->flags |= FS_APPEND_FL; 29 + if (fa->fsx_xflags & FS_XFLAG_SYNC) 30 + fa->flags |= FS_SYNC_FL; 31 + if (fa->fsx_xflags & FS_XFLAG_NOATIME) 32 + fa->flags |= FS_NOATIME_FL; 33 + if (fa->fsx_xflags & FS_XFLAG_NODUMP) 34 + fa->flags |= FS_NODUMP_FL; 35 + if (fa->fsx_xflags & FS_XFLAG_DAX) 36 + fa->flags |= FS_DAX_FL; 37 + if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) 38 + fa->flags |= FS_PROJINHERIT_FL; 39 + } 40 + EXPORT_SYMBOL(fileattr_fill_xflags); 41 + 42 + /** 43 + * fileattr_fill_flags - initialize fileattr with flags 44 + * @fa: fileattr pointer 45 + * @flags: FS_*_FL flags 46 + * 47 + * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags). 48 + * All other fields are zeroed. 49 + */ 50 + void fileattr_fill_flags(struct file_kattr *fa, u32 flags) 51 + { 52 + memset(fa, 0, sizeof(*fa)); 53 + fa->flags_valid = true; 54 + fa->flags = flags; 55 + if (fa->flags & FS_SYNC_FL) 56 + fa->fsx_xflags |= FS_XFLAG_SYNC; 57 + if (fa->flags & FS_IMMUTABLE_FL) 58 + fa->fsx_xflags |= FS_XFLAG_IMMUTABLE; 59 + if (fa->flags & FS_APPEND_FL) 60 + fa->fsx_xflags |= FS_XFLAG_APPEND; 61 + if (fa->flags & FS_NODUMP_FL) 62 + fa->fsx_xflags |= FS_XFLAG_NODUMP; 63 + if (fa->flags & FS_NOATIME_FL) 64 + fa->fsx_xflags |= FS_XFLAG_NOATIME; 65 + if (fa->flags & FS_DAX_FL) 66 + fa->fsx_xflags |= FS_XFLAG_DAX; 67 + if (fa->flags & FS_PROJINHERIT_FL) 68 + fa->fsx_xflags |= FS_XFLAG_PROJINHERIT; 69 + } 70 + EXPORT_SYMBOL(fileattr_fill_flags); 71 + 72 + /** 73 + * vfs_fileattr_get - retrieve miscellaneous file attributes 74 + * @dentry: the object to retrieve from 75 + * @fa: fileattr pointer 76 + * 77 + * Call i_op->fileattr_get() callback, if exists. 78 + * 79 + * Return: 0 on success, or a negative error on failure. 80 + */ 81 + int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 82 + { 83 + struct inode *inode = d_inode(dentry); 84 + int error; 85 + 86 + if (!inode->i_op->fileattr_get) 87 + return -EOPNOTSUPP; 88 + 89 + error = security_inode_file_getattr(dentry, fa); 90 + if (error) 91 + return error; 92 + 93 + return inode->i_op->fileattr_get(dentry, fa); 94 + } 95 + EXPORT_SYMBOL(vfs_fileattr_get); 96 + 97 + static void fileattr_to_file_attr(const struct file_kattr *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 + 110 + /** 111 + * copy_fsxattr_to_user - copy fsxattr to userspace. 112 + * @fa: fileattr pointer 113 + * @ufa: fsxattr user pointer 114 + * 115 + * Return: 0 on success, or -EFAULT on failure. 116 + */ 117 + int copy_fsxattr_to_user(const struct file_kattr *fa, struct fsxattr __user *ufa) 118 + { 119 + struct fsxattr xfa; 120 + __u32 mask = FS_XFLAGS_MASK; 121 + 122 + memset(&xfa, 0, sizeof(xfa)); 123 + xfa.fsx_xflags = fa->fsx_xflags & mask; 124 + xfa.fsx_extsize = fa->fsx_extsize; 125 + xfa.fsx_nextents = fa->fsx_nextents; 126 + xfa.fsx_projid = fa->fsx_projid; 127 + xfa.fsx_cowextsize = fa->fsx_cowextsize; 128 + 129 + if (copy_to_user(ufa, &xfa, sizeof(xfa))) 130 + return -EFAULT; 131 + 132 + return 0; 133 + } 134 + EXPORT_SYMBOL(copy_fsxattr_to_user); 135 + 136 + static int file_attr_to_fileattr(const struct file_attr *fattr, 137 + struct file_kattr *fa) 138 + { 139 + __u64 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 + 153 + static int copy_fsxattr_from_user(struct file_kattr *fa, 154 + struct fsxattr __user *ufa) 155 + { 156 + struct fsxattr xfa; 157 + __u32 mask = FS_XFLAGS_MASK; 158 + 159 + if (copy_from_user(&xfa, ufa, sizeof(xfa))) 160 + return -EFAULT; 161 + 162 + if (xfa.fsx_xflags & ~mask) 163 + return -EOPNOTSUPP; 164 + 165 + fileattr_fill_xflags(fa, xfa.fsx_xflags); 166 + fa->fsx_xflags &= ~FS_XFLAG_RDONLY_MASK; 167 + fa->fsx_extsize = xfa.fsx_extsize; 168 + fa->fsx_nextents = xfa.fsx_nextents; 169 + fa->fsx_projid = xfa.fsx_projid; 170 + fa->fsx_cowextsize = xfa.fsx_cowextsize; 171 + 172 + return 0; 173 + } 174 + 175 + /* 176 + * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject 177 + * any invalid configurations. 178 + * 179 + * Note: must be called with inode lock held. 180 + */ 181 + static int fileattr_set_prepare(struct inode *inode, 182 + const struct file_kattr *old_ma, 183 + struct file_kattr *fa) 184 + { 185 + int err; 186 + 187 + /* 188 + * The IMMUTABLE and APPEND_ONLY flags can only be changed by 189 + * the relevant capability. 190 + */ 191 + if ((fa->flags ^ old_ma->flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && 192 + !capable(CAP_LINUX_IMMUTABLE)) 193 + return -EPERM; 194 + 195 + err = fscrypt_prepare_setflags(inode, old_ma->flags, fa->flags); 196 + if (err) 197 + return err; 198 + 199 + /* 200 + * Project Quota ID state is only allowed to change from within the init 201 + * namespace. Enforce that restriction only if we are trying to change 202 + * the quota ID state. Everything else is allowed in user namespaces. 203 + */ 204 + if (current_user_ns() != &init_user_ns) { 205 + if (old_ma->fsx_projid != fa->fsx_projid) 206 + return -EINVAL; 207 + if ((old_ma->fsx_xflags ^ fa->fsx_xflags) & 208 + FS_XFLAG_PROJINHERIT) 209 + return -EINVAL; 210 + } else { 211 + /* 212 + * Caller is allowed to change the project ID. If it is being 213 + * changed, make sure that the new value is valid. 214 + */ 215 + if (old_ma->fsx_projid != fa->fsx_projid && 216 + !projid_valid(make_kprojid(&init_user_ns, fa->fsx_projid))) 217 + return -EINVAL; 218 + } 219 + 220 + /* Check extent size hints. */ 221 + if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode)) 222 + return -EINVAL; 223 + 224 + if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && 225 + !S_ISDIR(inode->i_mode)) 226 + return -EINVAL; 227 + 228 + if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) && 229 + !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) 230 + return -EINVAL; 231 + 232 + /* 233 + * It is only valid to set the DAX flag on regular files and 234 + * directories on filesystems. 235 + */ 236 + if ((fa->fsx_xflags & FS_XFLAG_DAX) && 237 + !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) 238 + return -EINVAL; 239 + 240 + /* Extent size hints of zero turn off the flags. */ 241 + if (fa->fsx_extsize == 0) 242 + fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); 243 + if (fa->fsx_cowextsize == 0) 244 + fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; 245 + 246 + return 0; 247 + } 248 + 249 + /** 250 + * vfs_fileattr_set - change miscellaneous file attributes 251 + * @idmap: idmap of the mount 252 + * @dentry: the object to change 253 + * @fa: fileattr pointer 254 + * 255 + * After verifying permissions, call i_op->fileattr_set() callback, if 256 + * exists. 257 + * 258 + * Verifying attributes involves retrieving current attributes with 259 + * i_op->fileattr_get(), this also allows initializing attributes that have 260 + * not been set by the caller to current values. Inode lock is held 261 + * thoughout to prevent racing with another instance. 262 + * 263 + * Return: 0 on success, or a negative error on failure. 264 + */ 265 + int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, 266 + struct file_kattr *fa) 267 + { 268 + struct inode *inode = d_inode(dentry); 269 + struct file_kattr old_ma = {}; 270 + int err; 271 + 272 + if (!inode->i_op->fileattr_set) 273 + return -EOPNOTSUPP; 274 + 275 + if (!inode_owner_or_capable(idmap, inode)) 276 + return -EPERM; 277 + 278 + inode_lock(inode); 279 + err = vfs_fileattr_get(dentry, &old_ma); 280 + if (!err) { 281 + /* initialize missing bits from old_ma */ 282 + if (fa->flags_valid) { 283 + fa->fsx_xflags |= old_ma.fsx_xflags & ~FS_XFLAG_COMMON; 284 + fa->fsx_extsize = old_ma.fsx_extsize; 285 + fa->fsx_nextents = old_ma.fsx_nextents; 286 + fa->fsx_projid = old_ma.fsx_projid; 287 + fa->fsx_cowextsize = old_ma.fsx_cowextsize; 288 + } else { 289 + fa->flags |= old_ma.flags & ~FS_COMMON_FL; 290 + } 291 + 292 + err = fileattr_set_prepare(inode, &old_ma, fa); 293 + if (err) 294 + goto out; 295 + err = security_inode_file_setattr(dentry, fa); 296 + if (err) 297 + goto out; 298 + err = inode->i_op->fileattr_set(idmap, dentry, fa); 299 + if (err) 300 + goto out; 301 + } 302 + 303 + out: 304 + inode_unlock(inode); 305 + return err; 306 + } 307 + EXPORT_SYMBOL(vfs_fileattr_set); 308 + 309 + int ioctl_getflags(struct file *file, unsigned int __user *argp) 310 + { 311 + struct file_kattr fa = { .flags_valid = true }; /* hint only */ 312 + int err; 313 + 314 + err = vfs_fileattr_get(file->f_path.dentry, &fa); 315 + if (err == -EOPNOTSUPP) 316 + err = -ENOIOCTLCMD; 317 + if (!err) 318 + err = put_user(fa.flags, argp); 319 + return err; 320 + } 321 + EXPORT_SYMBOL(ioctl_getflags); 322 + 323 + int ioctl_setflags(struct file *file, unsigned int __user *argp) 324 + { 325 + struct mnt_idmap *idmap = file_mnt_idmap(file); 326 + struct dentry *dentry = file->f_path.dentry; 327 + struct file_kattr fa; 328 + unsigned int flags; 329 + int err; 330 + 331 + err = get_user(flags, argp); 332 + if (!err) { 333 + err = mnt_want_write_file(file); 334 + if (!err) { 335 + fileattr_fill_flags(&fa, flags); 336 + err = vfs_fileattr_set(idmap, dentry, &fa); 337 + mnt_drop_write_file(file); 338 + if (err == -EOPNOTSUPP) 339 + err = -ENOIOCTLCMD; 340 + } 341 + } 342 + return err; 343 + } 344 + EXPORT_SYMBOL(ioctl_setflags); 345 + 346 + int ioctl_fsgetxattr(struct file *file, void __user *argp) 347 + { 348 + struct file_kattr fa = { .fsx_valid = true }; /* hint only */ 349 + int err; 350 + 351 + err = vfs_fileattr_get(file->f_path.dentry, &fa); 352 + if (err == -EOPNOTSUPP) 353 + err = -ENOIOCTLCMD; 354 + if (!err) 355 + err = copy_fsxattr_to_user(&fa, argp); 356 + 357 + return err; 358 + } 359 + EXPORT_SYMBOL(ioctl_fsgetxattr); 360 + 361 + int ioctl_fssetxattr(struct file *file, void __user *argp) 362 + { 363 + struct mnt_idmap *idmap = file_mnt_idmap(file); 364 + struct dentry *dentry = file->f_path.dentry; 365 + struct file_kattr fa; 366 + int err; 367 + 368 + err = copy_fsxattr_from_user(&fa, argp); 369 + if (!err) { 370 + err = mnt_want_write_file(file); 371 + if (!err) { 372 + err = vfs_fileattr_set(idmap, dentry, &fa); 373 + mnt_drop_write_file(file); 374 + if (err == -EOPNOTSUPP) 375 + err = -ENOIOCTLCMD; 376 + } 377 + } 378 + return err; 379 + } 380 + 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 file_kattr 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 file_kattr 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 + }
+2 -2
fs/fuse/fuse_i.h
··· 1479 1479 long fuse_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 1480 1480 long fuse_file_compat_ioctl(struct file *file, unsigned int cmd, 1481 1481 unsigned long arg); 1482 - int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa); 1482 + int fuse_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 1483 1483 int fuse_fileattr_set(struct mnt_idmap *idmap, 1484 - struct dentry *dentry, struct fileattr *fa); 1484 + struct dentry *dentry, struct file_kattr *fa); 1485 1485 1486 1486 /* iomode.c */ 1487 1487 int fuse_file_cached_io_open(struct inode *inode, struct fuse_file *ff);
+6 -2
fs/fuse/ioctl.c
··· 502 502 fuse_file_release(inode, ff, O_RDONLY, NULL, S_ISDIR(inode->i_mode)); 503 503 } 504 504 505 - int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa) 505 + int fuse_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 506 506 { 507 507 struct inode *inode = d_inode(dentry); 508 508 struct fuse_file *ff; ··· 536 536 cleanup: 537 537 fuse_priv_ioctl_cleanup(inode, ff); 538 538 539 + if (err == -ENOTTY) 540 + err = -EOPNOTSUPP; 539 541 return err; 540 542 } 541 543 542 544 int fuse_fileattr_set(struct mnt_idmap *idmap, 543 - struct dentry *dentry, struct fileattr *fa) 545 + struct dentry *dentry, struct file_kattr *fa) 544 546 { 545 547 struct inode *inode = d_inode(dentry); 546 548 struct fuse_file *ff; ··· 574 572 cleanup: 575 573 fuse_priv_ioctl_cleanup(inode, ff); 576 574 575 + if (err == -ENOTTY) 576 + err = -EOPNOTSUPP; 577 577 return err; 578 578 }
+2 -2
fs/gfs2/file.c
··· 155 155 return fsflags; 156 156 } 157 157 158 - int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa) 158 + int gfs2_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 159 159 { 160 160 struct inode *inode = d_inode(dentry); 161 161 struct gfs2_inode *ip = GFS2_I(inode); ··· 276 276 } 277 277 278 278 int gfs2_fileattr_set(struct mnt_idmap *idmap, 279 - struct dentry *dentry, struct fileattr *fa) 279 + struct dentry *dentry, struct file_kattr *fa) 280 280 { 281 281 struct inode *inode = d_inode(dentry); 282 282 u32 fsflags = fa->flags, gfsflags = 0;
+2 -2
fs/gfs2/inode.h
··· 107 107 extern const struct file_operations gfs2_file_fops_nolock; 108 108 extern const struct file_operations gfs2_dir_fops_nolock; 109 109 110 - int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa); 110 + int gfs2_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 111 111 int gfs2_fileattr_set(struct mnt_idmap *idmap, 112 - struct dentry *dentry, struct fileattr *fa); 112 + struct dentry *dentry, struct file_kattr *fa); 113 113 void gfs2_set_inode_flags(struct inode *inode); 114 114 115 115 #ifdef CONFIG_GFS2_FS_LOCKING_DLM
+2 -2
fs/hfsplus/hfsplus_fs.h
··· 491 491 unsigned int query_flags); 492 492 int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, 493 493 int datasync); 494 - int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa); 494 + int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 495 495 int hfsplus_fileattr_set(struct mnt_idmap *idmap, 496 - struct dentry *dentry, struct fileattr *fa); 496 + struct dentry *dentry, struct file_kattr *fa); 497 497 498 498 /* ioctl.c */ 499 499 long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+2 -2
fs/hfsplus/inode.c
··· 656 656 return res; 657 657 } 658 658 659 - int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa) 659 + int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 660 660 { 661 661 struct inode *inode = d_inode(dentry); 662 662 struct hfsplus_inode_info *hip = HFSPLUS_I(inode); ··· 675 675 } 676 676 677 677 int hfsplus_fileattr_set(struct mnt_idmap *idmap, 678 - struct dentry *dentry, struct fileattr *fa) 678 + struct dentry *dentry, struct file_kattr *fa) 679 679 { 680 680 struct inode *inode = d_inode(dentry); 681 681 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
-309
fs/ioctl.c
··· 453 453 return ret; 454 454 } 455 455 456 - /** 457 - * fileattr_fill_xflags - initialize fileattr with xflags 458 - * @fa: fileattr pointer 459 - * @xflags: FS_XFLAG_* flags 460 - * 461 - * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All 462 - * other fields are zeroed. 463 - */ 464 - void fileattr_fill_xflags(struct fileattr *fa, u32 xflags) 465 - { 466 - memset(fa, 0, sizeof(*fa)); 467 - fa->fsx_valid = true; 468 - fa->fsx_xflags = xflags; 469 - if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE) 470 - fa->flags |= FS_IMMUTABLE_FL; 471 - if (fa->fsx_xflags & FS_XFLAG_APPEND) 472 - fa->flags |= FS_APPEND_FL; 473 - if (fa->fsx_xflags & FS_XFLAG_SYNC) 474 - fa->flags |= FS_SYNC_FL; 475 - if (fa->fsx_xflags & FS_XFLAG_NOATIME) 476 - fa->flags |= FS_NOATIME_FL; 477 - if (fa->fsx_xflags & FS_XFLAG_NODUMP) 478 - fa->flags |= FS_NODUMP_FL; 479 - if (fa->fsx_xflags & FS_XFLAG_DAX) 480 - fa->flags |= FS_DAX_FL; 481 - if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT) 482 - fa->flags |= FS_PROJINHERIT_FL; 483 - } 484 - EXPORT_SYMBOL(fileattr_fill_xflags); 485 - 486 - /** 487 - * fileattr_fill_flags - initialize fileattr with flags 488 - * @fa: fileattr pointer 489 - * @flags: FS_*_FL flags 490 - * 491 - * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags). 492 - * All other fields are zeroed. 493 - */ 494 - void fileattr_fill_flags(struct fileattr *fa, u32 flags) 495 - { 496 - memset(fa, 0, sizeof(*fa)); 497 - fa->flags_valid = true; 498 - fa->flags = flags; 499 - if (fa->flags & FS_SYNC_FL) 500 - fa->fsx_xflags |= FS_XFLAG_SYNC; 501 - if (fa->flags & FS_IMMUTABLE_FL) 502 - fa->fsx_xflags |= FS_XFLAG_IMMUTABLE; 503 - if (fa->flags & FS_APPEND_FL) 504 - fa->fsx_xflags |= FS_XFLAG_APPEND; 505 - if (fa->flags & FS_NODUMP_FL) 506 - fa->fsx_xflags |= FS_XFLAG_NODUMP; 507 - if (fa->flags & FS_NOATIME_FL) 508 - fa->fsx_xflags |= FS_XFLAG_NOATIME; 509 - if (fa->flags & FS_DAX_FL) 510 - fa->fsx_xflags |= FS_XFLAG_DAX; 511 - if (fa->flags & FS_PROJINHERIT_FL) 512 - fa->fsx_xflags |= FS_XFLAG_PROJINHERIT; 513 - } 514 - EXPORT_SYMBOL(fileattr_fill_flags); 515 - 516 - /** 517 - * vfs_fileattr_get - retrieve miscellaneous file attributes 518 - * @dentry: the object to retrieve from 519 - * @fa: fileattr pointer 520 - * 521 - * Call i_op->fileattr_get() callback, if exists. 522 - * 523 - * Return: 0 on success, or a negative error on failure. 524 - */ 525 - int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 526 - { 527 - struct inode *inode = d_inode(dentry); 528 - 529 - if (!inode->i_op->fileattr_get) 530 - return -ENOIOCTLCMD; 531 - 532 - return inode->i_op->fileattr_get(dentry, fa); 533 - } 534 - EXPORT_SYMBOL(vfs_fileattr_get); 535 - 536 - /** 537 - * copy_fsxattr_to_user - copy fsxattr to userspace. 538 - * @fa: fileattr pointer 539 - * @ufa: fsxattr user pointer 540 - * 541 - * Return: 0 on success, or -EFAULT on failure. 542 - */ 543 - int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa) 544 - { 545 - struct fsxattr xfa; 546 - 547 - memset(&xfa, 0, sizeof(xfa)); 548 - xfa.fsx_xflags = fa->fsx_xflags; 549 - xfa.fsx_extsize = fa->fsx_extsize; 550 - xfa.fsx_nextents = fa->fsx_nextents; 551 - xfa.fsx_projid = fa->fsx_projid; 552 - xfa.fsx_cowextsize = fa->fsx_cowextsize; 553 - 554 - if (copy_to_user(ufa, &xfa, sizeof(xfa))) 555 - return -EFAULT; 556 - 557 - return 0; 558 - } 559 - EXPORT_SYMBOL(copy_fsxattr_to_user); 560 - 561 - static int copy_fsxattr_from_user(struct fileattr *fa, 562 - struct fsxattr __user *ufa) 563 - { 564 - struct fsxattr xfa; 565 - 566 - if (copy_from_user(&xfa, ufa, sizeof(xfa))) 567 - return -EFAULT; 568 - 569 - fileattr_fill_xflags(fa, xfa.fsx_xflags); 570 - fa->fsx_extsize = xfa.fsx_extsize; 571 - fa->fsx_nextents = xfa.fsx_nextents; 572 - fa->fsx_projid = xfa.fsx_projid; 573 - fa->fsx_cowextsize = xfa.fsx_cowextsize; 574 - 575 - return 0; 576 - } 577 - 578 - /* 579 - * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject 580 - * any invalid configurations. 581 - * 582 - * Note: must be called with inode lock held. 583 - */ 584 - static int fileattr_set_prepare(struct inode *inode, 585 - const struct fileattr *old_ma, 586 - struct fileattr *fa) 587 - { 588 - int err; 589 - 590 - /* 591 - * The IMMUTABLE and APPEND_ONLY flags can only be changed by 592 - * the relevant capability. 593 - */ 594 - if ((fa->flags ^ old_ma->flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && 595 - !capable(CAP_LINUX_IMMUTABLE)) 596 - return -EPERM; 597 - 598 - err = fscrypt_prepare_setflags(inode, old_ma->flags, fa->flags); 599 - if (err) 600 - return err; 601 - 602 - /* 603 - * Project Quota ID state is only allowed to change from within the init 604 - * namespace. Enforce that restriction only if we are trying to change 605 - * the quota ID state. Everything else is allowed in user namespaces. 606 - */ 607 - if (current_user_ns() != &init_user_ns) { 608 - if (old_ma->fsx_projid != fa->fsx_projid) 609 - return -EINVAL; 610 - if ((old_ma->fsx_xflags ^ fa->fsx_xflags) & 611 - FS_XFLAG_PROJINHERIT) 612 - return -EINVAL; 613 - } else { 614 - /* 615 - * Caller is allowed to change the project ID. If it is being 616 - * changed, make sure that the new value is valid. 617 - */ 618 - if (old_ma->fsx_projid != fa->fsx_projid && 619 - !projid_valid(make_kprojid(&init_user_ns, fa->fsx_projid))) 620 - return -EINVAL; 621 - } 622 - 623 - /* Check extent size hints. */ 624 - if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode)) 625 - return -EINVAL; 626 - 627 - if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && 628 - !S_ISDIR(inode->i_mode)) 629 - return -EINVAL; 630 - 631 - if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) && 632 - !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) 633 - return -EINVAL; 634 - 635 - /* 636 - * It is only valid to set the DAX flag on regular files and 637 - * directories on filesystems. 638 - */ 639 - if ((fa->fsx_xflags & FS_XFLAG_DAX) && 640 - !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) 641 - return -EINVAL; 642 - 643 - /* Extent size hints of zero turn off the flags. */ 644 - if (fa->fsx_extsize == 0) 645 - fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); 646 - if (fa->fsx_cowextsize == 0) 647 - fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; 648 - 649 - return 0; 650 - } 651 - 652 - /** 653 - * vfs_fileattr_set - change miscellaneous file attributes 654 - * @idmap: idmap of the mount 655 - * @dentry: the object to change 656 - * @fa: fileattr pointer 657 - * 658 - * After verifying permissions, call i_op->fileattr_set() callback, if 659 - * exists. 660 - * 661 - * Verifying attributes involves retrieving current attributes with 662 - * i_op->fileattr_get(), this also allows initializing attributes that have 663 - * not been set by the caller to current values. Inode lock is held 664 - * thoughout to prevent racing with another instance. 665 - * 666 - * Return: 0 on success, or a negative error on failure. 667 - */ 668 - int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, 669 - struct fileattr *fa) 670 - { 671 - struct inode *inode = d_inode(dentry); 672 - struct fileattr old_ma = {}; 673 - int err; 674 - 675 - if (!inode->i_op->fileattr_set) 676 - return -ENOIOCTLCMD; 677 - 678 - if (!inode_owner_or_capable(idmap, inode)) 679 - return -EPERM; 680 - 681 - inode_lock(inode); 682 - err = vfs_fileattr_get(dentry, &old_ma); 683 - if (!err) { 684 - /* initialize missing bits from old_ma */ 685 - if (fa->flags_valid) { 686 - fa->fsx_xflags |= old_ma.fsx_xflags & ~FS_XFLAG_COMMON; 687 - fa->fsx_extsize = old_ma.fsx_extsize; 688 - fa->fsx_nextents = old_ma.fsx_nextents; 689 - fa->fsx_projid = old_ma.fsx_projid; 690 - fa->fsx_cowextsize = old_ma.fsx_cowextsize; 691 - } else { 692 - fa->flags |= old_ma.flags & ~FS_COMMON_FL; 693 - } 694 - err = fileattr_set_prepare(inode, &old_ma, fa); 695 - if (!err) 696 - err = inode->i_op->fileattr_set(idmap, dentry, fa); 697 - } 698 - inode_unlock(inode); 699 - 700 - return err; 701 - } 702 - EXPORT_SYMBOL(vfs_fileattr_set); 703 - 704 - static int ioctl_getflags(struct file *file, unsigned int __user *argp) 705 - { 706 - struct fileattr fa = { .flags_valid = true }; /* hint only */ 707 - int err; 708 - 709 - err = vfs_fileattr_get(file->f_path.dentry, &fa); 710 - if (!err) 711 - err = put_user(fa.flags, argp); 712 - return err; 713 - } 714 - 715 - static int ioctl_setflags(struct file *file, unsigned int __user *argp) 716 - { 717 - struct mnt_idmap *idmap = file_mnt_idmap(file); 718 - struct dentry *dentry = file->f_path.dentry; 719 - struct fileattr fa; 720 - unsigned int flags; 721 - int err; 722 - 723 - err = get_user(flags, argp); 724 - if (!err) { 725 - err = mnt_want_write_file(file); 726 - if (!err) { 727 - fileattr_fill_flags(&fa, flags); 728 - err = vfs_fileattr_set(idmap, dentry, &fa); 729 - mnt_drop_write_file(file); 730 - } 731 - } 732 - return err; 733 - } 734 - 735 - static int ioctl_fsgetxattr(struct file *file, void __user *argp) 736 - { 737 - struct fileattr fa = { .fsx_valid = true }; /* hint only */ 738 - int err; 739 - 740 - err = vfs_fileattr_get(file->f_path.dentry, &fa); 741 - if (!err) 742 - err = copy_fsxattr_to_user(&fa, argp); 743 - 744 - return err; 745 - } 746 - 747 - static int ioctl_fssetxattr(struct file *file, void __user *argp) 748 - { 749 - struct mnt_idmap *idmap = file_mnt_idmap(file); 750 - struct dentry *dentry = file->f_path.dentry; 751 - struct fileattr fa; 752 - int err; 753 - 754 - err = copy_fsxattr_from_user(&fa, argp); 755 - if (!err) { 756 - err = mnt_want_write_file(file); 757 - if (!err) { 758 - err = vfs_fileattr_set(idmap, dentry, &fa); 759 - mnt_drop_write_file(file); 760 - } 761 - } 762 - return err; 763 - } 764 - 765 456 static int ioctl_getfsuuid(struct file *file, void __user *argp) 766 457 { 767 458 struct super_block *sb = file_inode(file)->i_sb;
+2 -2
fs/jfs/ioctl.c
··· 57 57 return mapped; 58 58 } 59 59 60 - int jfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 60 + int jfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 61 61 { 62 62 struct jfs_inode_info *jfs_inode = JFS_IP(d_inode(dentry)); 63 63 unsigned int flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE; ··· 71 71 } 72 72 73 73 int jfs_fileattr_set(struct mnt_idmap *idmap, 74 - struct dentry *dentry, struct fileattr *fa) 74 + struct dentry *dentry, struct file_kattr *fa) 75 75 { 76 76 struct inode *inode = d_inode(dentry); 77 77 struct jfs_inode_info *jfs_inode = JFS_IP(inode);
+2 -2
fs/jfs/jfs_inode.h
··· 9 9 10 10 extern struct inode *ialloc(struct inode *, umode_t); 11 11 extern int jfs_fsync(struct file *, loff_t, loff_t, int); 12 - extern int jfs_fileattr_get(struct dentry *dentry, struct fileattr *fa); 12 + extern int jfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 13 13 extern int jfs_fileattr_set(struct mnt_idmap *idmap, 14 - struct dentry *dentry, struct fileattr *fa); 14 + struct dentry *dentry, struct file_kattr *fa); 15 15 extern long jfs_ioctl(struct file *, unsigned int, unsigned long); 16 16 extern struct inode *jfs_iget(struct super_block *, unsigned long); 17 17 extern int jfs_commit_inode(struct inode *, int);
+2 -2
fs/nilfs2/ioctl.c
··· 118 118 * 119 119 * Return: always 0 as success. 120 120 */ 121 - int nilfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 121 + int nilfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 122 122 { 123 123 struct inode *inode = d_inode(dentry); 124 124 ··· 136 136 * Return: 0 on success, or a negative error code on failure. 137 137 */ 138 138 int nilfs_fileattr_set(struct mnt_idmap *idmap, 139 - struct dentry *dentry, struct fileattr *fa) 139 + struct dentry *dentry, struct file_kattr *fa) 140 140 { 141 141 struct inode *inode = d_inode(dentry); 142 142 struct nilfs_transaction_info ti;
+2 -2
fs/nilfs2/nilfs.h
··· 268 268 extern int nilfs_sync_file(struct file *, loff_t, loff_t, int); 269 269 270 270 /* ioctl.c */ 271 - int nilfs_fileattr_get(struct dentry *dentry, struct fileattr *m); 271 + int nilfs_fileattr_get(struct dentry *dentry, struct file_kattr *m); 272 272 int nilfs_fileattr_set(struct mnt_idmap *idmap, 273 - struct dentry *dentry, struct fileattr *fa); 273 + struct dentry *dentry, struct file_kattr *fa); 274 274 long nilfs_ioctl(struct file *, unsigned int, unsigned long); 275 275 long nilfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 276 276 int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *, struct nilfs_argv *,
+2 -2
fs/ocfs2/ioctl.c
··· 62 62 return (!(req->ir_flags & OCFS2_INFO_FL_NON_COHERENT)); 63 63 } 64 64 65 - int ocfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa) 65 + int ocfs2_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 66 66 { 67 67 struct inode *inode = d_inode(dentry); 68 68 unsigned int flags; ··· 83 83 } 84 84 85 85 int ocfs2_fileattr_set(struct mnt_idmap *idmap, 86 - struct dentry *dentry, struct fileattr *fa) 86 + struct dentry *dentry, struct file_kattr *fa) 87 87 { 88 88 struct inode *inode = d_inode(dentry); 89 89 unsigned int flags = fa->flags;
+2 -2
fs/ocfs2/ioctl.h
··· 11 11 #ifndef OCFS2_IOCTL_PROTO_H 12 12 #define OCFS2_IOCTL_PROTO_H 13 13 14 - int ocfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa); 14 + int ocfs2_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 15 15 int ocfs2_fileattr_set(struct mnt_idmap *idmap, 16 - struct dentry *dentry, struct fileattr *fa); 16 + struct dentry *dentry, struct file_kattr *fa); 17 17 long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 18 18 long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg); 19 19
+2 -2
fs/orangefs/inode.c
··· 889 889 return __orangefs_setattr(inode, &iattr); 890 890 } 891 891 892 - static int orangefs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 892 + static int orangefs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 893 893 { 894 894 u64 val = 0; 895 895 int ret; ··· 910 910 } 911 911 912 912 static int orangefs_fileattr_set(struct mnt_idmap *idmap, 913 - struct dentry *dentry, struct fileattr *fa) 913 + struct dentry *dentry, struct file_kattr *fa) 914 914 { 915 915 u64 val = 0; 916 916
+3 -3
fs/overlayfs/copy_up.c
··· 171 171 static int ovl_copy_fileattr(struct inode *inode, const struct path *old, 172 172 const struct path *new) 173 173 { 174 - struct fileattr oldfa = { .flags_valid = true }; 175 - struct fileattr newfa = { .flags_valid = true }; 174 + struct file_kattr oldfa = { .flags_valid = true }; 175 + struct file_kattr newfa = { .flags_valid = true }; 176 176 int err; 177 177 178 178 err = ovl_real_fileattr_get(old, &oldfa); 179 179 if (err) { 180 180 /* Ntfs-3g returns -EINVAL for "no fileattr support" */ 181 - if (err == -ENOTTY || err == -EINVAL) 181 + if (err == -EOPNOTSUPP || err == -EINVAL) 182 182 return 0; 183 183 pr_warn("failed to retrieve lower fileattr (%pd2, err=%i)\n", 184 184 old->dentry, err);
+7 -10
fs/overlayfs/inode.c
··· 610 610 * Introducing security_inode_fileattr_get/set() hooks would solve this issue 611 611 * properly. 612 612 */ 613 - static int ovl_security_fileattr(const struct path *realpath, struct fileattr *fa, 613 + static int ovl_security_fileattr(const struct path *realpath, struct file_kattr *fa, 614 614 bool set) 615 615 { 616 616 struct file *file; ··· 637 637 return err; 638 638 } 639 639 640 - int ovl_real_fileattr_set(const struct path *realpath, struct fileattr *fa) 640 + int ovl_real_fileattr_set(const struct path *realpath, struct file_kattr *fa) 641 641 { 642 642 int err; 643 643 ··· 649 649 } 650 650 651 651 int ovl_fileattr_set(struct mnt_idmap *idmap, 652 - struct dentry *dentry, struct fileattr *fa) 652 + struct dentry *dentry, struct file_kattr *fa) 653 653 { 654 654 struct inode *inode = d_inode(dentry); 655 655 struct path upperpath; ··· 697 697 } 698 698 699 699 /* Convert inode protection flags to fileattr flags */ 700 - static void ovl_fileattr_prot_flags(struct inode *inode, struct fileattr *fa) 700 + static void ovl_fileattr_prot_flags(struct inode *inode, struct file_kattr *fa) 701 701 { 702 702 BUILD_BUG_ON(OVL_PROT_FS_FLAGS_MASK & ~FS_COMMON_FL); 703 703 BUILD_BUG_ON(OVL_PROT_FSX_FLAGS_MASK & ~FS_XFLAG_COMMON); ··· 712 712 } 713 713 } 714 714 715 - int ovl_real_fileattr_get(const struct path *realpath, struct fileattr *fa) 715 + int ovl_real_fileattr_get(const struct path *realpath, struct file_kattr *fa) 716 716 { 717 717 int err; 718 718 ··· 720 720 if (err) 721 721 return err; 722 722 723 - err = vfs_fileattr_get(realpath->dentry, fa); 724 - if (err == -ENOIOCTLCMD) 725 - err = -ENOTTY; 726 - return err; 723 + return vfs_fileattr_get(realpath->dentry, fa); 727 724 } 728 725 729 - int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa) 726 + int ovl_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 730 727 { 731 728 struct inode *inode = d_inode(dentry); 732 729 struct path realpath;
+5 -5
fs/overlayfs/overlayfs.h
··· 838 838 839 839 void ovl_check_protattr(struct inode *inode, struct dentry *upper); 840 840 int ovl_set_protattr(struct inode *inode, struct dentry *upper, 841 - struct fileattr *fa); 841 + struct file_kattr *fa); 842 842 843 843 static inline void ovl_copyflags(struct inode *from, struct inode *to) 844 844 { ··· 870 870 871 871 /* file.c */ 872 872 extern const struct file_operations ovl_file_operations; 873 - int ovl_real_fileattr_get(const struct path *realpath, struct fileattr *fa); 874 - int ovl_real_fileattr_set(const struct path *realpath, struct fileattr *fa); 875 - int ovl_fileattr_get(struct dentry *dentry, struct fileattr *fa); 873 + int ovl_real_fileattr_get(const struct path *realpath, struct file_kattr *fa); 874 + int ovl_real_fileattr_set(const struct path *realpath, struct file_kattr *fa); 875 + int ovl_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 876 876 int ovl_fileattr_set(struct mnt_idmap *idmap, 877 - struct dentry *dentry, struct fileattr *fa); 877 + struct dentry *dentry, struct file_kattr *fa); 878 878 struct ovl_file; 879 879 struct ovl_file *ovl_file_alloc(struct file *realfile); 880 880 void ovl_file_free(struct ovl_file *of);
+1 -1
fs/overlayfs/util.c
··· 966 966 } 967 967 968 968 int ovl_set_protattr(struct inode *inode, struct dentry *upper, 969 - struct fileattr *fa) 969 + struct file_kattr *fa) 970 970 { 971 971 struct ovl_fs *ofs = OVL_FS(inode->i_sb); 972 972 char buf[OVL_PROTATTR_MAX];
+2 -2
fs/ubifs/ioctl.c
··· 130 130 return err; 131 131 } 132 132 133 - int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 133 + int ubifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 134 134 { 135 135 struct inode *inode = d_inode(dentry); 136 136 int flags = ubifs2ioctl(ubifs_inode(inode)->flags); ··· 145 145 } 146 146 147 147 int ubifs_fileattr_set(struct mnt_idmap *idmap, 148 - struct dentry *dentry, struct fileattr *fa) 148 + struct dentry *dentry, struct file_kattr *fa) 149 149 { 150 150 struct inode *inode = d_inode(dentry); 151 151 int flags = fa->flags;
+2 -2
fs/ubifs/ubifs.h
··· 2073 2073 void ubifs_destroy_size_tree(struct ubifs_info *c); 2074 2074 2075 2075 /* ioctl.c */ 2076 - int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa); 2076 + int ubifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 2077 2077 int ubifs_fileattr_set(struct mnt_idmap *idmap, 2078 - struct dentry *dentry, struct fileattr *fa); 2078 + struct dentry *dentry, struct file_kattr *fa); 2079 2079 long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 2080 2080 void ubifs_set_inode_flags(struct inode *inode); 2081 2081 #ifdef CONFIG_COMPAT
+9 -9
fs/xfs/xfs_ioctl.c
··· 444 444 xfs_fill_fsxattr( 445 445 struct xfs_inode *ip, 446 446 int whichfork, 447 - struct fileattr *fa) 447 + struct file_kattr *fa) 448 448 { 449 449 struct xfs_mount *mp = ip->i_mount; 450 450 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); ··· 496 496 xfs_inode_t *ip, 497 497 void __user *arg) 498 498 { 499 - struct fileattr fa; 499 + struct file_kattr fa; 500 500 501 501 xfs_ilock(ip, XFS_ILOCK_SHARED); 502 502 xfs_fill_fsxattr(ip, XFS_ATTR_FORK, &fa); ··· 508 508 int 509 509 xfs_fileattr_get( 510 510 struct dentry *dentry, 511 - struct fileattr *fa) 511 + struct file_kattr *fa) 512 512 { 513 513 struct xfs_inode *ip = XFS_I(d_inode(dentry)); 514 514 ··· 526 526 xfs_ioctl_setattr_xflags( 527 527 struct xfs_trans *tp, 528 528 struct xfs_inode *ip, 529 - struct fileattr *fa) 529 + struct file_kattr *fa) 530 530 { 531 531 struct xfs_mount *mp = ip->i_mount; 532 532 bool rtflag = (fa->fsx_xflags & FS_XFLAG_REALTIME); ··· 582 582 static void 583 583 xfs_ioctl_setattr_prepare_dax( 584 584 struct xfs_inode *ip, 585 - struct fileattr *fa) 585 + struct file_kattr *fa) 586 586 { 587 587 struct xfs_mount *mp = ip->i_mount; 588 588 struct inode *inode = VFS_I(ip); ··· 642 642 static int 643 643 xfs_ioctl_setattr_check_extsize( 644 644 struct xfs_inode *ip, 645 - struct fileattr *fa) 645 + struct file_kattr *fa) 646 646 { 647 647 struct xfs_mount *mp = ip->i_mount; 648 648 xfs_failaddr_t failaddr; ··· 684 684 static int 685 685 xfs_ioctl_setattr_check_cowextsize( 686 686 struct xfs_inode *ip, 687 - struct fileattr *fa) 687 + struct file_kattr *fa) 688 688 { 689 689 struct xfs_mount *mp = ip->i_mount; 690 690 xfs_failaddr_t failaddr; ··· 709 709 static int 710 710 xfs_ioctl_setattr_check_projid( 711 711 struct xfs_inode *ip, 712 - struct fileattr *fa) 712 + struct file_kattr *fa) 713 713 { 714 714 if (!fa->fsx_valid) 715 715 return 0; ··· 725 725 xfs_fileattr_set( 726 726 struct mnt_idmap *idmap, 727 727 struct dentry *dentry, 728 - struct fileattr *fa) 728 + struct file_kattr *fa) 729 729 { 730 730 struct xfs_inode *ip = XFS_I(d_inode(dentry)); 731 731 struct xfs_mount *mp = ip->i_mount;
+2 -2
fs/xfs/xfs_ioctl.h
··· 17 17 extern int 18 18 xfs_fileattr_get( 19 19 struct dentry *dentry, 20 - struct fileattr *fa); 20 + struct file_kattr *fa); 21 21 22 22 extern int 23 23 xfs_fileattr_set( 24 24 struct mnt_idmap *idmap, 25 25 struct dentry *dentry, 26 - struct fileattr *fa); 26 + struct file_kattr *fa); 27 27 28 28 extern long 29 29 xfs_file_ioctl(
+31 -7
include/linux/fileattr.h
··· 14 14 FS_XFLAG_NODUMP | FS_XFLAG_NOATIME | FS_XFLAG_DAX | \ 15 15 FS_XFLAG_PROJINHERIT) 16 16 17 + /* Read-only inode flags */ 18 + #define FS_XFLAG_RDONLY_MASK \ 19 + (FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR) 20 + 21 + /* Flags to indicate valid value of fsx_ fields */ 22 + #define FS_XFLAG_VALUES_MASK \ 23 + (FS_XFLAG_EXTSIZE | FS_XFLAG_COWEXTSIZE) 24 + 25 + /* Flags for directories */ 26 + #define FS_XFLAG_DIRONLY_MASK \ 27 + (FS_XFLAG_RTINHERIT | FS_XFLAG_NOSYMLINKS | FS_XFLAG_EXTSZINHERIT) 28 + 29 + /* Misc settable flags */ 30 + #define FS_XFLAG_MISC_MASK \ 31 + (FS_XFLAG_REALTIME | FS_XFLAG_NODEFRAG | FS_XFLAG_FILESTREAM) 32 + 33 + #define FS_XFLAGS_MASK \ 34 + (FS_XFLAG_COMMON | FS_XFLAG_RDONLY_MASK | FS_XFLAG_VALUES_MASK | \ 35 + FS_XFLAG_DIRONLY_MASK | FS_XFLAG_MISC_MASK) 36 + 17 37 /* 18 38 * Merged interface for miscellaneous file attributes. 'flags' originates from 19 39 * ext* and 'fsx_flags' from xfs. There's some overlap between the two, which 20 40 * is handled by the VFS helpers, so filesystems are free to implement just one 21 41 * or both of these sub-interfaces. 22 42 */ 23 - struct fileattr { 43 + struct file_kattr { 24 44 u32 flags; /* flags (FS_IOC_GETFLAGS/FS_IOC_SETFLAGS) */ 25 45 /* struct fsxattr: */ 26 46 u32 fsx_xflags; /* xflags field value (get/set) */ ··· 53 33 bool fsx_valid:1; 54 34 }; 55 35 56 - int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa); 36 + int copy_fsxattr_to_user(const struct file_kattr *fa, struct fsxattr __user *ufa); 57 37 58 - void fileattr_fill_xflags(struct fileattr *fa, u32 xflags); 59 - void fileattr_fill_flags(struct fileattr *fa, u32 flags); 38 + void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags); 39 + void fileattr_fill_flags(struct file_kattr *fa, u32 flags); 60 40 61 41 /** 62 42 * fileattr_has_fsx - check for extended flags/attributes ··· 65 45 * Return: true if any attributes are present that are not represented in 66 46 * ->flags. 67 47 */ 68 - static inline bool fileattr_has_fsx(const struct fileattr *fa) 48 + static inline bool fileattr_has_fsx(const struct file_kattr *fa) 69 49 { 70 50 return fa->fsx_valid && 71 51 ((fa->fsx_xflags & ~FS_XFLAG_COMMON) || fa->fsx_extsize != 0 || 72 52 fa->fsx_projid != 0 || fa->fsx_cowextsize != 0); 73 53 } 74 54 75 - int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa); 55 + int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); 76 56 int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, 77 - struct fileattr *fa); 57 + struct file_kattr *fa); 58 + int ioctl_getflags(struct file *file, unsigned int __user *argp); 59 + int ioctl_setflags(struct file *file, unsigned int __user *argp); 60 + int ioctl_fsgetxattr(struct file *file, void __user *argp); 61 + int ioctl_fssetxattr(struct file *file, void __user *argp); 78 62 79 63 #endif /* _LINUX_FILEATTR_H */
+3 -3
include/linux/fs.h
··· 80 80 struct fsnotify_sb_info; 81 81 struct fs_context; 82 82 struct fs_parameter_spec; 83 - struct fileattr; 83 + struct file_kattr; 84 84 struct iomap_ops; 85 85 86 86 extern void __init inode_init(void); ··· 2257 2257 int (*set_acl)(struct mnt_idmap *, struct dentry *, 2258 2258 struct posix_acl *, int); 2259 2259 int (*fileattr_set)(struct mnt_idmap *idmap, 2260 - struct dentry *dentry, struct fileattr *fa); 2261 - int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); 2260 + struct dentry *dentry, struct file_kattr *fa); 2261 + int (*fileattr_get)(struct dentry *dentry, struct file_kattr *fa); 2262 2262 struct offset_ctx *(*get_offset_ctx)(struct inode *inode); 2263 2263 } ____cacheline_aligned; 2264 2264
+2
include/linux/lsm_hook_defs.h
··· 157 157 struct dentry *dentry, const char *name) 158 158 LSM_HOOK(void, LSM_RET_VOID, inode_post_removexattr, struct dentry *dentry, 159 159 const char *name) 160 + LSM_HOOK(int, 0, inode_file_setattr, struct dentry *dentry, struct file_kattr *fa) 161 + LSM_HOOK(int, 0, inode_file_getattr, struct dentry *dentry, struct file_kattr *fa) 160 162 LSM_HOOK(int, 0, inode_set_acl, struct mnt_idmap *idmap, 161 163 struct dentry *dentry, const char *acl_name, struct posix_acl *kacl) 162 164 LSM_HOOK(void, LSM_RET_VOID, inode_post_set_acl, struct dentry *dentry,
+16
include/linux/security.h
··· 451 451 int security_inode_removexattr(struct mnt_idmap *idmap, 452 452 struct dentry *dentry, const char *name); 453 453 void security_inode_post_removexattr(struct dentry *dentry, const char *name); 454 + int security_inode_file_setattr(struct dentry *dentry, 455 + struct file_kattr *fa); 456 + int security_inode_file_getattr(struct dentry *dentry, 457 + struct file_kattr *fa); 454 458 int security_inode_need_killpriv(struct dentry *dentry); 455 459 int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry); 456 460 int security_inode_getsecurity(struct mnt_idmap *idmap, ··· 1055 1051 static inline void security_inode_post_removexattr(struct dentry *dentry, 1056 1052 const char *name) 1057 1053 { } 1054 + 1055 + static inline int security_inode_file_setattr(struct dentry *dentry, 1056 + struct file_kattr *fa) 1057 + { 1058 + return 0; 1059 + } 1060 + 1061 + static inline int security_inode_file_getattr(struct dentry *dentry, 1062 + struct file_kattr *fa) 1063 + { 1064 + return 0; 1065 + } 1058 1066 1059 1067 static inline int security_inode_need_killpriv(struct dentry *dentry) 1060 1068 {
+7
include/linux/syscalls.h
··· 78 78 struct statmount; 79 79 struct mnt_id_req; 80 80 struct xattr_args; 81 + struct file_attr; 81 82 82 83 #include <linux/types.h> 83 84 #include <linux/aio_abi.h> ··· 372 371 asmlinkage long sys_lremovexattr(const char __user *path, 373 372 const char __user *name); 374 373 asmlinkage long sys_fremovexattr(int fd, const char __user *name); 374 + asmlinkage long sys_file_getattr(int dfd, const char __user *filename, 375 + struct file_attr __user *attr, size_t usize, 376 + unsigned int at_flags); 377 + asmlinkage long sys_file_setattr(int dfd, const char __user *filename, 378 + struct file_attr __user *attr, size_t usize, 379 + unsigned int at_flags); 375 380 asmlinkage long sys_getcwd(char __user *buf, unsigned long size); 376 381 asmlinkage long sys_eventfd2(unsigned int count, int flags); 377 382 asmlinkage long sys_epoll_create1(int flags);
+7 -1
include/uapi/asm-generic/unistd.h
··· 852 852 #define __NR_open_tree_attr 467 853 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 861 #undef __NR_syscalls 856 - #define __NR_syscalls 468 862 + #define __NR_syscalls 470 857 863 858 864 /* 859 865 * 32 bit systems traditionally used different
+18
include/uapi/linux/fs.h
··· 217 217 }; 218 218 219 219 /* 220 + * Variable size structure for file_[sg]et_attr(). 221 + * 222 + * Note. This is alternative to the structure 'struct file_kattr'/'struct fsxattr'. 223 + * As this structure is passed to/from userspace with its size, this can 224 + * be versioned based on the size. 225 + */ 226 + struct file_attr { 227 + __u64 fa_xflags; /* xflags field value (get/set) */ 228 + __u32 fa_extsize; /* extsize field value (get/set)*/ 229 + __u32 fa_nextents; /* nextents field value (get) */ 230 + __u32 fa_projid; /* project identifier (get/set) */ 231 + __u32 fa_cowextsize; /* CoW extsize field value (get/set) */ 232 + }; 233 + 234 + #define FILE_ATTR_SIZE_VER0 24 235 + #define FILE_ATTR_SIZE_LATEST FILE_ATTR_SIZE_VER0 236 + 237 + /* 220 238 * Flags for the fsx_xflags field 221 239 */ 222 240 #define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */
+2 -2
mm/shmem.c
··· 4187 4187 4188 4188 #ifdef CONFIG_TMPFS_XATTR 4189 4189 4190 - static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa) 4190 + static int shmem_fileattr_get(struct dentry *dentry, struct file_kattr *fa) 4191 4191 { 4192 4192 struct shmem_inode_info *info = SHMEM_I(d_inode(dentry)); 4193 4193 ··· 4197 4197 } 4198 4198 4199 4199 static int shmem_fileattr_set(struct mnt_idmap *idmap, 4200 - struct dentry *dentry, struct fileattr *fa) 4200 + struct dentry *dentry, struct file_kattr *fa) 4201 4201 { 4202 4202 struct inode *inode = d_inode(dentry); 4203 4203 struct shmem_inode_info *info = SHMEM_I(inode);
+2
scripts/syscall.tbl
··· 408 408 465 common listxattrat sys_listxattrat 409 409 466 common removexattrat sys_removexattrat 410 410 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
+30
security/security.c
··· 2623 2623 } 2624 2624 2625 2625 /** 2626 + * security_inode_file_setattr() - check if setting fsxattr is allowed 2627 + * @dentry: file to set filesystem extended attributes on 2628 + * @fa: extended attributes to set on the inode 2629 + * 2630 + * Called when file_setattr() syscall or FS_IOC_FSSETXATTR ioctl() is called on 2631 + * inode 2632 + * 2633 + * Return: Returns 0 if permission is granted. 2634 + */ 2635 + int security_inode_file_setattr(struct dentry *dentry, struct file_kattr *fa) 2636 + { 2637 + return call_int_hook(inode_file_setattr, dentry, fa); 2638 + } 2639 + 2640 + /** 2641 + * security_inode_file_getattr() - check if retrieving fsxattr is allowed 2642 + * @dentry: file to retrieve filesystem extended attributes from 2643 + * @fa: extended attributes to get 2644 + * 2645 + * Called when file_getattr() syscall or FS_IOC_FSGETXATTR ioctl() is called on 2646 + * inode 2647 + * 2648 + * Return: Returns 0 if permission is granted. 2649 + */ 2650 + int security_inode_file_getattr(struct dentry *dentry, struct file_kattr *fa) 2651 + { 2652 + return call_int_hook(inode_file_getattr, dentry, fa); 2653 + } 2654 + 2655 + /** 2626 2656 * security_inode_need_killpriv() - Check if security_inode_killpriv() required 2627 2657 * @dentry: associated dentry 2628 2658 *
+14
security/selinux/hooks.c
··· 3480 3480 return -EACCES; 3481 3481 } 3482 3482 3483 + static int selinux_inode_file_setattr(struct dentry *dentry, 3484 + struct file_kattr *fa) 3485 + { 3486 + return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); 3487 + } 3488 + 3489 + static int selinux_inode_file_getattr(struct dentry *dentry, 3490 + struct file_kattr *fa) 3491 + { 3492 + return dentry_has_perm(current_cred(), dentry, FILE__GETATTR); 3493 + } 3494 + 3483 3495 static int selinux_path_notify(const struct path *path, u64 mask, 3484 3496 unsigned int obj_type) 3485 3497 { ··· 7362 7350 LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr), 7363 7351 LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr), 7364 7352 LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr), 7353 + LSM_HOOK_INIT(inode_file_getattr, selinux_inode_file_getattr), 7354 + LSM_HOOK_INIT(inode_file_setattr, selinux_inode_file_setattr), 7365 7355 LSM_HOOK_INIT(inode_set_acl, selinux_inode_set_acl), 7366 7356 LSM_HOOK_INIT(inode_get_acl, selinux_inode_get_acl), 7367 7357 LSM_HOOK_INIT(inode_remove_acl, selinux_inode_remove_acl),