Implement unprivileged chroot
This builds on recently introduced NO_NEW_PRIVS flag to implement unprivileged chroot, enabled by `security.bsd.unprivileged_chroot`. It allows non-root processes to chroot(2), provided they have the NO_NEW_PRIVS flag set. The chroot(8) utility gets a new flag, -n, which sets NO_NEW_PRIVS before chrooting. Reviewed By: kib Sponsored By: EPSRC Relnotes: yes Differential Revision: https://reviews.freebsd.org/D30130
This commit is contained in:
parent
27ab791a55
commit
a40cf4175c
@ -955,6 +955,10 @@ kern_chdir(struct thread *td, const char *path, enum uio_seg pathseg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -967,11 +971,20 @@ int
|
||||
sys_chroot(struct thread *td, struct chroot_args *uap)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct proc *p;
|
||||
int error;
|
||||
|
||||
error = priv_check(td, PRIV_VFS_CHROOT);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (error != 0) {
|
||||
p = td->td_proc;
|
||||
PROC_LOCK(p);
|
||||
if (unprivileged_chroot == 0 ||
|
||||
(p->p_flag2 & P2_NO_NEW_PRIVS) == 0) {
|
||||
PROC_UNLOCK(p);
|
||||
return (error);
|
||||
}
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1,
|
||||
UIO_USERSPACE, uap->path, td);
|
||||
error = namei(&nd);
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" @(#)chroot.8 8.1 (Berkeley) 6/9/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 27, 2020
|
||||
.Dd July 20, 2021
|
||||
.Dt CHROOT 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -39,6 +39,7 @@
|
||||
.Op Fl G Ar group Ns Op Cm \&, Ns Ar group ...
|
||||
.Op Fl g Ar group
|
||||
.Op Fl u Ar user
|
||||
.Op Fl n
|
||||
.Ar newroot
|
||||
.Op Ar command Op Ar arg ...
|
||||
.Sh DESCRIPTION
|
||||
@ -61,6 +62,16 @@ Run the command with the permissions of the specified
|
||||
.It Fl u Ar user
|
||||
Run the command as the
|
||||
.Ar user .
|
||||
.It Fl n
|
||||
Use the
|
||||
.Dv PROC_NO_NEW_PRIVS_CTL
|
||||
.Xr procctl 2
|
||||
command before chrooting, effectively disabling SUID/SGID bits
|
||||
for the calling process and its descendants.
|
||||
If
|
||||
.Dv security.bsd.unprivileged_chroot
|
||||
sysctl is set to 1, it will make it possible to chroot without
|
||||
superuser privileges.
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
The following environment variable is referenced by
|
||||
|
@ -44,6 +44,7 @@ static char sccsid[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93";
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/procctl.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
@ -51,6 +52,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <pwd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -67,13 +69,15 @@ main(int argc, char *argv[])
|
||||
const char *shell;
|
||||
gid_t gid, *gidlist;
|
||||
uid_t uid;
|
||||
int ch, gids;
|
||||
int arg, ch, error, gids;
|
||||
long ngroups_max;
|
||||
bool nonpriviledged;
|
||||
|
||||
gid = 0;
|
||||
uid = 0;
|
||||
user = group = grouplist = NULL;
|
||||
while ((ch = getopt(argc, argv, "G:g:u:")) != -1) {
|
||||
nonpriviledged = false;
|
||||
while ((ch = getopt(argc, argv, "G:g:u:n")) != -1) {
|
||||
switch(ch) {
|
||||
case 'u':
|
||||
user = optarg;
|
||||
@ -90,6 +94,9 @@ main(int argc, char *argv[])
|
||||
if (*grouplist == '\0')
|
||||
usage();
|
||||
break;
|
||||
case 'n':
|
||||
nonpriviledged = true;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
@ -153,6 +160,13 @@ main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (nonpriviledged) {
|
||||
arg = PROC_NO_NEW_PRIVS_ENABLE;
|
||||
error = procctl(P_PID, getpid(), PROC_NO_NEW_PRIVS_CTL, &arg);
|
||||
if (error != 0)
|
||||
err(1, "procctl");
|
||||
}
|
||||
|
||||
if (chdir(argv[0]) == -1 || chroot(".") == -1)
|
||||
err(1, "%s", argv[0]);
|
||||
|
||||
@ -179,6 +193,6 @@ static void
|
||||
usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
|
||||
"[-u user] newroot [command]\n");
|
||||
"[-u user] [-n ] newroot [command]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user