diff options
| author | Edward Tomasz Napierala <trasz@FreeBSD.org> | 2024-11-29 07:46:07 +0000 |
|---|---|---|
| committer | Edward Tomasz Napierala <trasz@FreeBSD.org> | 2024-11-29 12:10:02 +0000 |
| commit | b165e9e3ea4e327fc421d81c2a89242bd8720780 (patch) | |
| tree | cee64e3fcfa6d5fa66ab2399c0f80e19c02d64a5 /sys | |
| parent | 347dd0539f3a75fdf2128dd4620ca99e96f311e9 (diff) | |
Add fchroot(2)
This is similar to chroot(2), but takes a file descriptor instead
of path. Same syscall exists in NetBSD and Solaris. It is part of a larger
patch to make absolute pathnames usable in Capsicum mode, but should
be useful in other contexts too.
Reviewed By: brooks
Sponsored by: Innovate UK
Differential Revision: https://reviews.freebsd.org/D41564
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/kern/subr_capability.c | 2 | ||||
| -rw-r--r-- | sys/kern/syscalls.master | 5 | ||||
| -rw-r--r-- | sys/kern/vfs_syscalls.c | 84 | ||||
| -rw-r--r-- | sys/sys/caprights.h | 1 | ||||
| -rw-r--r-- | sys/sys/capsicum.h | 7 |
5 files changed, 74 insertions, 25 deletions
diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c index 1f3a181a91cb..a97c16d6d7df 100644 --- a/sys/kern/subr_capability.c +++ b/sys/kern/subr_capability.c @@ -59,6 +59,7 @@ __read_mostly cap_rights_t cap_fchdir_rights; __read_mostly cap_rights_t cap_fchflags_rights; __read_mostly cap_rights_t cap_fchmod_rights; __read_mostly cap_rights_t cap_fchown_rights; +__read_mostly cap_rights_t cap_fchroot_rights; __read_mostly cap_rights_t cap_fcntl_rights; __read_mostly cap_rights_t cap_fexecve_rights; __read_mostly cap_rights_t cap_flock_rights; @@ -108,6 +109,7 @@ cap_rights_sysinit(void *arg) cap_rights_init_one(&cap_fchflags_rights, CAP_FCHFLAGS); cap_rights_init_one(&cap_fchmod_rights, CAP_FCHMOD); cap_rights_init_one(&cap_fchown_rights, CAP_FCHOWN); + cap_rights_init_one(&cap_fchroot_rights, CAP_FCHROOT); cap_rights_init_one(&cap_fcntl_rights, CAP_FCNTL); cap_rights_init_one(&cap_fexecve_rights, CAP_FEXECVE); cap_rights_init_one(&cap_flock_rights, CAP_FLOCK); diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 2bbd20b5a5b0..e7f577d48426 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3341,5 +3341,10 @@ _Out_ rlim_t *res ); } +590 AUE_NULL STD { + int fchroot( + int fd + ); + } ; vim: syntax=off diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index ab0e562e73aa..7a1677c945e3 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -967,18 +967,13 @@ static int unprivileged_chroot = 0; SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_chroot, CTLFLAG_RW, &unprivileged_chroot, 0, "Unprivileged processes can use chroot(2)"); + /* - * Change notion of root (``/'') directory. + * Takes locked vnode, unlocks it before returning. */ -#ifndef _SYS_SYSPROTO_H_ -struct chroot_args { - char *path; -}; -#endif -int -sys_chroot(struct thread *td, struct chroot_args *uap) +static int +kern_chroot(struct thread *td, struct vnode *vp) { - struct nameidata nd; struct proc *p; int error; @@ -989,30 +984,75 @@ sys_chroot(struct thread *td, struct chroot_args *uap) if (unprivileged_chroot == 0 || (p->p_flag2 & P2_NO_NEW_PRIVS) == 0) { PROC_UNLOCK(p); - return (error); + goto e_vunlock; } PROC_UNLOCK(p); } - NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, - UIO_USERSPACE, uap->path); - error = namei(&nd); - if (error != 0) - return (error); - NDFREE_PNBUF(&nd); - error = change_dir(nd.ni_vp, td); + + error = change_dir(vp, td); if (error != 0) goto e_vunlock; #ifdef MAC - error = mac_vnode_check_chroot(td->td_ucred, nd.ni_vp); + error = mac_vnode_check_chroot(td->td_ucred, vp); if (error != 0) goto e_vunlock; #endif - VOP_UNLOCK(nd.ni_vp); - error = pwd_chroot(td, nd.ni_vp); - vrele(nd.ni_vp); + VOP_UNLOCK(vp); + error = pwd_chroot(td, vp); + vrele(vp); return (error); e_vunlock: - vput(nd.ni_vp); + vput(vp); + return (error); +} + +/* + * Change notion of root (``/'') directory. + */ +#ifndef _SYS_SYSPROTO_H_ +struct chroot_args { + char *path; +}; +#endif +int +sys_chroot(struct thread *td, struct chroot_args *uap) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1, + UIO_USERSPACE, uap->path); + error = namei(&nd); + if (error != 0) + return (error); + NDFREE_PNBUF(&nd); + error = kern_chroot(td, nd.ni_vp); + return (error); +} + +/* + * Change notion of root directory to a given file descriptor. + */ +#ifndef _SYS_SYSPROTO_H_ +struct fchroot_args { + int fd; +}; +#endif +int +sys_fchroot(struct thread *td, struct fchroot_args *uap) +{ + struct vnode *vp; + struct file *fp; + int error; + + error = getvnode_path(td, uap->fd, &cap_fchroot_rights, &fp); + if (error != 0) + return (error); + vp = fp->f_vnode; + vrefact(vp); + fdrop(fp, td); + vn_lock(vp, LK_SHARED | LK_RETRY); + error = kern_chroot(td, vp); return (error); } diff --git a/sys/sys/caprights.h b/sys/sys/caprights.h index 32ae05172e24..62711545114d 100644 --- a/sys/sys/caprights.h +++ b/sys/sys/caprights.h @@ -66,6 +66,7 @@ extern cap_rights_t cap_fchdir_rights; extern cap_rights_t cap_fchflags_rights; extern cap_rights_t cap_fchmod_rights; extern cap_rights_t cap_fchown_rights; +extern cap_rights_t cap_fchroot_rights; extern cap_rights_t cap_fcntl_rights; extern cap_rights_t cap_fexecve_rights; extern cap_rights_t cap_flock_rights; diff --git a/sys/sys/capsicum.h b/sys/sys/capsicum.h index 5c6813d2a450..9b50986ede0a 100644 --- a/sys/sys/capsicum.h +++ b/sys/sys/capsicum.h @@ -201,6 +201,9 @@ /* Allows for renameat(2) (target directory descriptor). */ #define CAP_RENAMEAT_TARGET (CAP_LOOKUP | 0x0000040000000000ULL) +/* Allows for fchroot(2). */ +#define CAP_FCHROOT CAPRIGHT(0, 0x0000080000000000ULL) + #define CAP_SOCK_CLIENT \ (CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT | \ CAP_PEELOFF | CAP_RECV | CAP_SEND | CAP_SETSOCKOPT | CAP_SHUTDOWN) @@ -210,11 +213,9 @@ CAP_SETSOCKOPT | CAP_SHUTDOWN) /* All used bits for index 0. */ -#define CAP_ALL0 CAPRIGHT(0, 0x000007FFFFFFFFFFULL) +#define CAP_ALL0 CAPRIGHT(0, 0x00000FFFFFFFFFFFULL) /* Available bits for index 0. */ -#define CAP_UNUSED0_44 CAPRIGHT(0, 0x0000080000000000ULL) -/* ... */ #define CAP_UNUSED0_57 CAPRIGHT(0, 0x0100000000000000ULL) /* INDEX 1 */ |
