dhclient: Don't chroot if we are in capability mode.

The main dhclient process is Capsicumized but also chroots to
restrict filesystem access.  With r322369, pidfile(3) maintains a
directory descriptor for the pidfile, which can cause the chroot
to fail in certain cases.  To minimize the problem, only chroot
if we fail to enter capability mode, and store dhclient pidfiles
in a subdirectory of /var/run, thus restricting access via
pidfile(3)'s directory descriptor.

PR:		223327
Reviewed by:	cem, oshogbo
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D16584
This commit is contained in:
Mark Johnston 2018-08-06 16:22:01 +00:00
parent 7db2360401
commit 976e100378
4 changed files with 34 additions and 15 deletions

View File

@ -74,6 +74,8 @@
preserve
..
run
dhclient
..
ppp gname=network mode=0770
..
wpa_supplicant

View File

@ -38,7 +38,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd October 13, 2011
.Dd August 4, 2018
.Dt DHCLIENT 8
.Os
.Sh NAME
@ -87,7 +87,7 @@ for the leases file.
.It Fl p Ar file
Specify an alternate location for the PID file.
The default is
.Pa /var/run/dhclient. Ns Ar interface Ns Pa .pid .
.Pa /var/run/dhclient/dhclient. Ns Ar interface Ns Pa .pid .
.It Fl q
Forces
.Nm
@ -194,3 +194,16 @@ and
.Pp
The current implementation was reworked by
.An Henning Brauer Aq Mt henning@openbsd.org .
.Sh BUGS
The
.Nm
utility uses
.Xr capsicum 4
to sandbox the main process.
If the requisite kernel support is not available, the main process will
attempt to run in a
.Xr chroot 2
sandbox instead.
This will fail if the process is jailed or the
.Va kern.chroot_allow_open_directories
sysctl is set to 0.

View File

@ -371,6 +371,7 @@ init_casper(void)
int
main(int argc, char *argv[])
{
u_int capmode;
int ch, fd, quiet = 0, i = 0;
int pipe_fd[2];
int immediate_daemon = 0;
@ -419,7 +420,7 @@ main(int argc, char *argv[])
if (path_dhclient_pidfile == NULL) {
asprintf(&path_dhclient_pidfile,
"%sdhclient.%s.pid", _PATH_VARRUN, *argv);
"%s/dhclient/dhclient.%s.pid", _PATH_VARRUN, *argv);
if (path_dhclient_pidfile == NULL)
error("asprintf");
}
@ -528,11 +529,6 @@ main(int argc, char *argv[])
if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
error("can't limit route socket: %m");
if (chroot(_PATH_VAREMPTY) == -1)
error("chroot");
if (chdir("/") == -1)
error("chdir(\"/\")");
if (setgroups(1, &pw->pw_gid) ||
setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
seteuid(pw->pw_uid) || setuid(pw->pw_uid))
@ -545,6 +541,19 @@ main(int argc, char *argv[])
if (caph_enter_casper() < 0)
error("can't enter capability mode: %m");
/*
* If we are not in capability mode (i.e., because Capsicum or
* libcasper is disabled), try to restrict filesystem access. This
* will fail if kern.chroot_allow_open_directories is 0 or the process
* is jailed.
*/
if (cap_getmode(&capmode) < 0 || capmode == 0) {
if (chroot(_PATH_VAREMPTY) == -1)
error("chroot");
if (chdir("/") == -1)
error("chdir(\"/\")");
}
if (immediate_daemon)
go_daemon();
@ -2449,13 +2458,8 @@ go_daemon(void)
cap_rights_init(&rights);
if (pidfile != NULL) {
if (pidfile != NULL)
pidfile_write(pidfile);
if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 &&
errno != ENOSYS) {
error("can't limit pidfile descriptor: %m");
}
}
if (nullfd != -1) {
close(nullfd);

View File

@ -14,7 +14,7 @@ ifn="$2"
name="dhclient"
desc="Dynamic Host Configuration Protocol (DHCP) client"
rcvar=
pidfile="/var/run/${name}.${ifn}.pid"
pidfile="/var/run/dhclient/${name}.${ifn}.pid"
start_precmd="dhclient_prestart"
stop_precmd="dhclient_pre_check"