aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorEdward Tomasz Napierala <trasz@FreeBSD.org>2024-11-29 07:46:07 +0000
committerEdward Tomasz Napierala <trasz@FreeBSD.org>2024-11-29 12:10:02 +0000
commitb165e9e3ea4e327fc421d81c2a89242bd8720780 (patch)
treecee64e3fcfa6d5fa66ab2399c0f80e19c02d64a5 /sys
parent347dd0539f3a75fdf2128dd4620ca99e96f311e9 (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.c2
-rw-r--r--sys/kern/syscalls.master5
-rw-r--r--sys/kern/vfs_syscalls.c84
-rw-r--r--sys/sys/caprights.h1
-rw-r--r--sys/sys/capsicum.h7
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 */