diff --git a/sys/compat/linux/linux_xattr.c b/sys/compat/linux/linux_xattr.c index b54a0d2f89ad..7de4484490f1 100644 --- a/sys/compat/linux/linux_xattr.c +++ b/sys/compat/linux/linux_xattr.c @@ -68,6 +68,22 @@ struct setxattr_args { int follow; }; +struct getxattr_args { + int fd; + const char *path; + const char *name; + void *value; + l_size_t size; + int follow; +}; + +struct removexattr_args { + int fd; + const char *path; + const char *name; + int follow; +}; + static char *extattr_namespace_names[] = EXTATTR_NAMESPACE_NAMES; @@ -172,7 +188,7 @@ listxattr(struct thread *td, struct listxattr_args *args) if (error == 0) td->td_retval[0] = cnt; free(data, M_LINUX); - return (error); + return (error == EPERM ? ENOTSUP : error); } int @@ -218,91 +234,123 @@ linux_flistxattr(struct thread *td, struct linux_flistxattr_args *args) } static int -linux_path_removexattr(struct thread *td, const char *upath, const char *uname, - int follow) +removexattr(struct thread *td, struct removexattr_args *args) { char attrname[LINUX_XATTR_NAME_MAX + 1]; int attrnamespace, error; - error = xatrr_to_extattr(uname, &attrnamespace, attrname); + error = xatrr_to_extattr(args->name, &attrnamespace, attrname); if (error != 0) return (error); - - return (kern_extattr_delete_path(td, upath, attrnamespace, - attrname, follow, UIO_USERSPACE)); + if (args->path != NULL) + error = kern_extattr_delete_path(td, args->path, attrnamespace, + attrname, args->follow, UIO_USERSPACE); + else + error = kern_extattr_delete_fd(td, args->fd, attrnamespace, + attrname); + return (error == EPERM ? ENOTSUP : error); } int linux_removexattr(struct thread *td, struct linux_removexattr_args *args) { + struct removexattr_args eargs = { + .fd = -1, + .path = args->path, + .name = args->name, + .follow = FOLLOW, + }; - return (linux_path_removexattr(td, args->path, args->name, - FOLLOW)); + return (removexattr(td, &eargs)); } int linux_lremovexattr(struct thread *td, struct linux_lremovexattr_args *args) { + struct removexattr_args eargs = { + .fd = -1, + .path = args->path, + .name = args->name, + .follow = NOFOLLOW, + }; - return (linux_path_removexattr(td, args->path, args->name, - NOFOLLOW)); + return (removexattr(td, &eargs)); } int linux_fremovexattr(struct thread *td, struct linux_fremovexattr_args *args) { - char attrname[LINUX_XATTR_NAME_MAX + 1]; - int attrnamespace, error; + struct removexattr_args eargs = { + .fd = args->fd, + .path = NULL, + .name = args->name, + .follow = 0, + }; - error = xatrr_to_extattr(args->name, &attrnamespace, attrname); - if (error != 0) - return (error); - return (kern_extattr_delete_fd(td, args->fd, attrnamespace, - attrname)); + return (removexattr(td, &eargs)); } static int -linux_path_getxattr(struct thread *td, const char *upath, const char *uname, - void *value, l_size_t size, int follow) +getxattr(struct thread *td, struct getxattr_args *args) { char attrname[LINUX_XATTR_NAME_MAX + 1]; int attrnamespace, error; - error = xatrr_to_extattr(uname, &attrnamespace, attrname); + error = xatrr_to_extattr(args->name, &attrnamespace, attrname); if (error != 0) return (error); - - return (kern_extattr_get_path(td, upath, attrnamespace, - attrname, value, size, follow, UIO_USERSPACE)); + if (args->path != NULL) + error = kern_extattr_get_path(td, args->path, attrnamespace, + attrname, args->value, args->size, args->follow, UIO_USERSPACE); + else + error = kern_extattr_get_fd(td, args->fd, attrnamespace, + attrname, args->value, args->size); + return (error == EPERM ? ENOATTR : error); } int linux_getxattr(struct thread *td, struct linux_getxattr_args *args) { + struct getxattr_args eargs = { + .fd = -1, + .path = args->path, + .name = args->name, + .value = args->value, + .size = args->size, + .follow = FOLLOW, + }; - return (linux_path_getxattr(td, args->path, args->name, - args->value, args->size, FOLLOW)); + return (getxattr(td, &eargs)); } int linux_lgetxattr(struct thread *td, struct linux_lgetxattr_args *args) { + struct getxattr_args eargs = { + .fd = -1, + .path = args->path, + .name = args->name, + .value = args->value, + .size = args->size, + .follow = NOFOLLOW, + }; - return (linux_path_getxattr(td, args->path, args->name, - args->value, args->size, NOFOLLOW)); + return (getxattr(td, &eargs)); } int linux_fgetxattr(struct thread *td, struct linux_fgetxattr_args *args) { - char attrname[LINUX_XATTR_NAME_MAX + 1]; - int attrnamespace, error; + struct getxattr_args eargs = { + .fd = args->fd, + .path = NULL, + .name = args->name, + .value = args->value, + .size = args->size, + .follow = 0, + }; - error = xatrr_to_extattr(args->name, &attrnamespace, attrname); - if (error != 0) - return (error); - return (kern_extattr_get_fd(td, args->fd, attrnamespace, - attrname, args->value, args->size)); + return (getxattr(td, &eargs)); } static int @@ -344,7 +392,7 @@ setxattr(struct thread *td, struct setxattr_args *args) attrname, args->value, args->size); out: td->td_retval[0] = 0; - return (error); + return (error == EPERM ? ENOTSUP : error); } int diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 39bdcaf5ef0e..130c46d52948 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -220,6 +220,7 @@ static struct bool_flags pr_flag_allow[NBBY * NBPW] = { #ifdef VIMAGE {"allow.nfsd", "allow.nonfsd", PR_ALLOW_NFSD}, #endif + {"allow.extattr", "allow.noextattr", PR_ALLOW_EXTATTR}, }; static unsigned pr_allow_all = PR_ALLOW_ALL_STATIC; const size_t pr_flag_allow_size = sizeof(pr_flag_allow); @@ -4059,6 +4060,12 @@ prison_priv_check(struct ucred *cred, int priv) case PRIV_VFS_READ_DIR: return (0); + case PRIV_VFS_EXTATTR_SYSTEM: + if (cred->cr_prison->pr_allow & PR_ALLOW_EXTATTR) + return (0); + else + return (EPERM); + /* * Conditionnaly allow locking (unlocking) physical pages * in memory. @@ -4552,6 +4559,8 @@ SYSCTL_JAIL_PARAM(_allow, suser, CTLTYPE_INT | CTLFLAG_RW, SYSCTL_JAIL_PARAM(_allow, nfsd, CTLTYPE_INT | CTLFLAG_RW, "B", "Mountd/nfsd may run in the jail"); #endif +SYSCTL_JAIL_PARAM(_allow, extattr, CTLTYPE_INT | CTLFLAG_RW, + "B", "Jail may set system-level filesystem extended attributes"); SYSCTL_JAIL_PARAM_SUBNODE(allow, mount, "Jail mount/unmount permission flags"); SYSCTL_JAIL_PARAM(_allow_mount, , CTLTYPE_INT | CTLFLAG_RW, diff --git a/sys/sys/jail.h b/sys/sys/jail.h index 088a0bc33d6d..fb8858f73453 100644 --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -253,7 +253,8 @@ struct prison_racct { #define PR_ALLOW_RESERVED_PORTS 0x00008000 #define PR_ALLOW_KMEM_ACCESS 0x00010000 /* reserved, not used yet */ #define PR_ALLOW_NFSD 0x00020000 -#define PR_ALLOW_ALL_STATIC 0x000387ff +#define PR_ALLOW_EXTATTR 0x00040000 +#define PR_ALLOW_ALL_STATIC 0x000787ff /* * PR_ALLOW_DIFFERENCES determines which flags are able to be diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 index 6fb5fdfa0623..2ed9de882165 100644 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 26, 2023 +.Dd September 4, 2023 .Dt JAIL 8 .Os .Sh NAME @@ -644,6 +644,9 @@ sysctl. The super-user will be disabled automatically if its parent system has it disabled. The super-user is enabled by default. +.It Va allow.extattr +Allow privileged process in the jail manipulate filesystem extended attributes +in the system namespace. .El .El .Pp @@ -1416,7 +1419,8 @@ environment of the first jail. .Xr shutdown 8 , .Xr sysctl 8 , .Xr syslogd 8 , -.Xr umount 8 +.Xr umount 8 , +.Xr extattr 9 .Sh HISTORY The .Nm