On Mon 30-06-25 18:20:16, Andrey Albershteyn wrote: > From: Andrey Albershteyn <aalbersh@xxxxxxxxxx> > > Introduce file_getattr() and file_setattr() syscalls to manipulate inode > extended attributes. The syscalls takes pair of file descriptor and > pathname. Then it operates on inode opened accroding to openat() ^^^ according > semantics. The struct fsx_fileattr is passed to obtain/change extended > attributes. > > This is an alternative to FS_IOC_FSSETXATTR ioctl with a difference > that file don't need to be open as we can reference it with a path ^^^ doesn't > instead of fd. By having this we can manipulated inode extended > attributes not only on regular files but also on special ones. This > is not possible with FS_IOC_FSSETXATTR ioctl as with special files > we can not call ioctl() directly on the filesystem inode using fd. > > This patch adds two new syscalls which allows userspace to get/set > extended inode attributes on special files by using parent directory > and a path - *at() like syscall. > > CC: linux-api@xxxxxxxxxxxxxxx > CC: linux-fsdevel@xxxxxxxxxxxxxxx > CC: linux-xfs@xxxxxxxxxxxxxxx > Signed-off-by: Andrey Albershteyn <aalbersh@xxxxxxxxxx> > Acked-by: Arnd Bergmann <arnd@xxxxxxxx> There's possible NULL ptr deref bug below (2x) that's easy to fix. Once done feel free to add: Reviewed-by: Jan Kara <jack@xxxxxxx> > @@ -343,3 +377,117 @@ int ioctl_fssetxattr(struct file *file, void __user *argp) > return err; > } > EXPORT_SYMBOL(ioctl_fssetxattr); > + > +SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename, > + struct fsx_fileattr __user *, ufsx, size_t, usize, > + unsigned int, at_flags) > +{ > + struct fileattr fa; > + struct path filepath __free(path_put) = {}; > + int error; > + unsigned int lookup_flags = 0; > + struct filename *name __free(putname) = NULL; > + struct fsx_fileattr fsx; > + > + BUILD_BUG_ON(sizeof(struct fsx_fileattr) < FSX_FILEATTR_SIZE_VER0); > + BUILD_BUG_ON(sizeof(struct fsx_fileattr) != FSX_FILEATTR_SIZE_LATEST); > + > + if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) > + return -EINVAL; > + > + if (!(at_flags & AT_SYMLINK_NOFOLLOW)) > + lookup_flags |= LOOKUP_FOLLOW; > + > + if (usize > PAGE_SIZE) > + return -E2BIG; > + > + if (usize < FSX_FILEATTR_SIZE_VER0) > + return -EINVAL; > + > + name = getname_maybe_null(filename, at_flags); > + if (IS_ERR(name)) > + return PTR_ERR(name); > + > + if (!name && dfd >= 0) { > + CLASS(fd, f)(dfd); > + > + filepath = fd_file(f)->f_path; If dfd is not correct fd, then this will dereference NULL AFAICT. I think you need here: if (fd_empty(f)) return -EBADF; > + path_get(&filepath); > + } else { > + error = filename_lookup(dfd, name, lookup_flags, &filepath, > + NULL); > + if (error) > + return error; > + } > + > + error = vfs_fileattr_get(filepath.dentry, &fa); > + if (error) > + return error; > + > + fileattr_to_fsx_fileattr(&fa, &fsx); > + error = copy_struct_to_user(ufsx, usize, &fsx, > + sizeof(struct fsx_fileattr), NULL); > + > + return error; > +} > + > +SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename, > + struct fsx_fileattr __user *, ufsx, size_t, usize, > + unsigned int, at_flags) > +{ > + struct fileattr fa; > + struct path filepath __free(path_put) = {}; > + int error; > + unsigned int lookup_flags = 0; > + struct filename *name __free(putname) = NULL; > + struct fsx_fileattr fsx; > + > + BUILD_BUG_ON(sizeof(struct fsx_fileattr) < FSX_FILEATTR_SIZE_VER0); > + BUILD_BUG_ON(sizeof(struct fsx_fileattr) != FSX_FILEATTR_SIZE_LATEST); > + > + if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) > + return -EINVAL; > + > + if (!(at_flags & AT_SYMLINK_NOFOLLOW)) > + lookup_flags |= LOOKUP_FOLLOW; > + > + if (usize > PAGE_SIZE) > + return -E2BIG; > + > + if (usize < FSX_FILEATTR_SIZE_VER0) > + return -EINVAL; > + > + error = copy_struct_from_user(&fsx, sizeof(struct fsx_fileattr), ufsx, > + usize); > + if (error) > + return error; > + > + error = fsx_fileattr_to_fileattr(&fsx, &fa); > + if (error) > + return error; > + > + name = getname_maybe_null(filename, at_flags); > + if (IS_ERR(name)) > + return PTR_ERR(name); > + > + if (!name && dfd >= 0) { > + CLASS(fd, f)(dfd); > + Same comment here as above. > + filepath = fd_file(f)->f_path; > + path_get(&filepath); > + } else { > + error = filename_lookup(dfd, name, lookup_flags, &filepath, > + NULL); > + if (error) > + return error; > + } > + > + error = mnt_want_write(filepath.mnt); > + if (!error) { > + error = vfs_fileattr_set(mnt_idmap(filepath.mnt), > + filepath.dentry, &fa); > + mnt_drop_write(filepath.mnt); > + } > + > + return error; > +} Honza -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR