@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
+}
@@ -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;
}
@@ -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);
@@ -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);
@@ -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