Page MenuHomeFreeBSD

D41564.1789946949.diff
No OneTemporary

Size
14 KB
Referenced Files
None
Subscribers
None

D41564.1789946949.diff

diff --git a/include/unistd.h b/include/unistd.h
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -468,6 +468,7 @@
#if (__XSI_VISIBLE && __XSI_VISIBLE <= 500) || __BSD_VISIBLE
int brk(const void *);
int chroot(const char *);
+int fchroot(int);
int getdtablesize(void);
int getpagesize(void) __pure2;
char *getpass(const char *);
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -377,6 +377,7 @@
MLINKS+=chown.2 fchown.2 \
chown.2 fchownat.2 \
chown.2 lchown.2
+MLINKS+=chroot.2 fchroot.2
MLINKS+=clock_gettime.2 clock_getres.2 \
clock_gettime.2 clock_settime.2
MLINKS+=closefrom.2 close_range.2
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -417,6 +417,7 @@
FBSD_1.7 {
_Fork;
+ fchroot;
fspacectl;
kqueuex;
membarrier;
diff --git a/lib/libc/sys/chroot.2 b/lib/libc/sys/chroot.2
--- a/lib/libc/sys/chroot.2
+++ b/lib/libc/sys/chroot.2
@@ -31,7 +31,8 @@
.Dt CHROOT 2
.Os
.Sh NAME
-.Nm chroot
+.Nm chroot ,
+.Nm fchroot
.Nd change root directory
.Sh LIBRARY
.Lb libc
@@ -39,6 +40,8 @@
.In unistd.h
.Ft int
.Fn chroot "const char *dirname"
+.Ft int
+.Fn fchroot "int fd"
.Sh DESCRIPTION
The
.Fa dirname
@@ -94,6 +97,12 @@
mimicking the historic insecure behavior of
.Fn chroot
still present on other systems.
+.Pp
+The
+.Fn fchroot
+is identical to
+.Fn chroot
+except it takes a file descriptor instead of path.
.Sh RETURN VALUES
.Rv -std
.Sh ERRORS
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -502,4 +502,5 @@
#define FREEBSD32_SYS_swapoff 582
#define FREEBSD32_SYS_kqueuex 583
#define FREEBSD32_SYS_membarrier 584
-#define FREEBSD32_SYS_MAXSYSCALL 585
+#define FREEBSD32_SYS_fchroot 585
+#define FREEBSD32_SYS_MAXSYSCALL 586
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -590,4 +590,5 @@
"swapoff", /* 582 = swapoff */
"kqueuex", /* 583 = kqueuex */
"membarrier", /* 584 = membarrier */
+ "fchroot", /* 585 = fchroot */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -646,4 +646,5 @@
{ .sy_narg = AS(swapoff_args), .sy_call = (sy_call_t *)sys_swapoff, .sy_auevent = AUE_SWAPOFF, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 582 = swapoff */
{ .sy_narg = AS(kqueuex_args), .sy_call = (sy_call_t *)sys_kqueuex, .sy_auevent = AUE_KQUEUE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 583 = kqueuex */
{ .sy_narg = AS(membarrier_args), .sy_call = (sy_call_t *)sys_membarrier, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 584 = membarrier */
+ { .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 585 = fchroot */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3336,6 +3336,13 @@
*n_args = 3;
break;
}
+ /* fchroot */
+ case 585: {
+ struct fchroot_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9005,6 +9012,16 @@
break;
};
break;
+ /* fchroot */
+ case 585:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -10873,6 +10890,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* fchroot */
+ case 585:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -645,4 +645,5 @@
{ .sy_narg = AS(swapoff_args), .sy_call = (sy_call_t *)sys_swapoff, .sy_auevent = AUE_SWAPOFF, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 582 = swapoff */
{ .sy_narg = AS(kqueuex_args), .sy_call = (sy_call_t *)sys_kqueuex, .sy_auevent = AUE_KQUEUE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 583 = kqueuex */
{ .sy_narg = AS(membarrier_args), .sy_call = (sy_call_t *)sys_membarrier, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 584 = membarrier */
+ { .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 585 = fchroot */
};
diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c
--- a/sys/kern/subr_capability.c
+++ b/sys/kern/subr_capability.c
@@ -59,6 +59,7 @@
__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_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.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -590,4 +590,5 @@
"swapoff", /* 582 = swapoff */
"kqueuex", /* 583 = kqueuex */
"membarrier", /* 584 = membarrier */
+ "fchroot", /* 585 = fchroot */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3318,6 +3318,10 @@
int cpu_id
);
}
-
+585 AUE_NULL STD {
+ int fchroot(
+ int fd,
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3432,6 +3432,13 @@
*n_args = 3;
break;
}
+ /* fchroot */
+ case 585: {
+ struct fchroot_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9175,6 +9182,16 @@
break;
};
break;
+ /* fchroot */
+ case 585:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11138,6 +11155,11 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* fchroot */
+ case 585:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -968,18 +968,13 @@
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;
@@ -990,30 +985,67 @@
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);
+}
+
+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
--- a/sys/sys/caprights.h
+++ b/sys/sys/caprights.h
@@ -66,6 +66,7 @@
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
--- a/sys/sys/capsicum.h
+++ b/sys/sys/capsicum.h
@@ -202,6 +202,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)
@@ -211,11 +214,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 */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -521,4 +521,5 @@
#define SYS_swapoff 582
#define SYS_kqueuex 583
#define SYS_membarrier 584
-#define SYS_MAXSYSCALL 585
+#define SYS_fchroot 585
+#define SYS_MAXSYSCALL 586
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -426,4 +426,5 @@
sched_getcpu.o \
swapoff.o \
kqueuex.o \
- membarrier.o
+ membarrier.o \
+ fchroot.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1862,6 +1862,9 @@
char flags_l_[PADL_(unsigned)]; unsigned flags; char flags_r_[PADR_(unsigned)];
char cpu_id_l_[PADL_(int)]; int cpu_id; char cpu_id_r_[PADR_(int)];
};
+struct fchroot_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+};
int sys_exit(struct thread *, struct exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2259,6 +2262,7 @@
int sys_swapoff(struct thread *, struct swapoff_args *);
int sys_kqueuex(struct thread *, struct kqueuex_args *);
int sys_membarrier(struct thread *, struct membarrier_args *);
+int sys_fchroot(struct thread *, struct fchroot_args *);
#ifdef COMPAT_43
@@ -3230,6 +3234,7 @@
#define SYS_AUE_swapoff AUE_SWAPOFF
#define SYS_AUE_kqueuex AUE_KQUEUE
#define SYS_AUE_membarrier AUE_NULL
+#define SYS_AUE_fchroot AUE_NULL
#undef PAD_
#undef PADL_
diff --git a/usr.sbin/chroot/chroot.8 b/usr.sbin/chroot/chroot.8
--- a/usr.sbin/chroot/chroot.8
+++ b/usr.sbin/chroot/chroot.8
@@ -35,6 +35,7 @@
.Nd change root directory
.Sh SYNOPSIS
.Nm
+.Op Fl d
.Op Fl G Ar group Ns Op Cm \&, Ns Ar group ...
.Op Fl g Ar group
.Op Fl u Ar user
@@ -53,6 +54,10 @@
.Pp
The options are as follows:
.Bl -tag -width "-G group[,group ...]"
+.It Fl d
+Assume the
+.Ar newroot
+is a file descriptor number and not a path.
.It Fl G Ar group Ns Op Cm \&, Ns Ar group ...
Run the command with the permissions of the specified groups.
.It Fl g Ar group
diff --git a/usr.sbin/chroot/chroot.c b/usr.sbin/chroot/chroot.c
--- a/usr.sbin/chroot/chroot.c
+++ b/usr.sbin/chroot/chroot.c
@@ -46,6 +46,7 @@
#include <ctype.h>
#include <err.h>
+#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <paths.h>
@@ -67,16 +68,19 @@
const char *shell;
gid_t gid, *gidlist;
uid_t uid;
- int arg, ch, error, gids;
+ int arg, ch, error, fd, gids;
long ngroups_max;
- bool nonprivileged;
+ bool nonprivileged, fd_not_path;
gid = 0;
uid = 0;
user = group = grouplist = NULL;
- nonprivileged = false;
- while ((ch = getopt(argc, argv, "G:g:u:n")) != -1) {
+ nonprivileged = fd_not_path = false;
+ while ((ch = getopt(argc, argv, "dG:g:u:n")) != -1) {
switch(ch) {
+ case 'd':
+ fd_not_path = true;
+ break;
case 'u':
user = optarg;
if (*user == '\0')
@@ -165,8 +169,20 @@
err(1, "procctl");
}
- if (chdir(argv[0]) == -1 || chroot(".") == -1)
- err(1, "%s", argv[0]);
+ if (fd_not_path) {
+ fd = (uid_t)strtoul(argv[0], &endp, 0);
+ if (*endp != '\0')
+ errx(1, "%s is not a number", argv[0]);
+ if (fchdir(fd) == -1)
+ err(1, "%s", argv[0]);
+ if (fchroot(fd) == -1)
+ err(1, "chroot");
+ } else {
+ if (chdir(argv[0]) == -1)
+ err(1, "%s", argv[0]);
+ if (chroot(".") == -1)
+ err(1, "chroot");
+ }
if (gids && setgroups(gids, gidlist) == -1)
err(1, "setgroups");
@@ -190,7 +206,8 @@
static void
usage(void)
{
- (void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
+ (void)fprintf(stderr,
+ "usage: chroot [-d] [-g group] [-G group,group,...] "
"[-u user] [-n] newroot [command]\n");
exit(1);
}

File Metadata

Mime Type
text/plain
Expires
Sun, Sep 20, 11:29 PM (10 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29828139
Default Alt Text
D41564.1789946949.diff (14 KB)

Event Timeline