In hardened systems, where the security.bsd.unprivileged_proc_debug sysctl

node is set, allow setting security.bsd.unprivileged_proc_debug per-jail.
In part, this is needed to create jails in which the Address Sanitizer
(ASAN) fully works as ASAN utilizes libkvm to inspect the virtual address
space. Instead of having to allow unprivileged process debugging for the
entire system, allow setting it on a per-jail basis.

The sysctl node is still security.bsd.unprivileged_proc_debug and the
jail(8) param is allow.unprivileged_proc_debug. The sysctl code is now a
sysctl proc rather than a sysctl int. This allows us to determine setting
the flag for the corresponding jail (or prison0).

As part of the change, the dynamic allow.* API needed to be modified to
take into account pr_allow flags which may now be disabled in prison0.
This prevents conflicts with new pr_allow flags (like that of vmm(4)) that
are added (and removed) dynamically.

Also teach the jail creation KPI to allow differences for certain pr_allow
flags between the parent and child jail. This can happen when unprivileged
process debugging is disabled in the parent prison, but enabled in the
child.

Submitted by:	Shawn Webb <lattera at gmail.com>
Obtained from:	HardenedBSD (45b3625edba0f73b3e3890b1ec3d0d1e95fd47e1, deba0b5078cef0faae43cbdafed3035b16587afc, ab21eeb3b4c72f2500987c96ff603ccf3b6e7de8)
Relnotes:	yes
Sponsored by:	HardenedBSD and G2, Inc
Differential Revision:	https://reviews.freebsd.org/D18319
This commit is contained in:
Jamie Gritton 2018-11-27 17:51:50 +00:00
parent 2636ba4d03
commit b307954481
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=341084
5 changed files with 75 additions and 15 deletions

View File

@ -194,10 +194,14 @@ static struct bool_flags pr_flag_allow[NBBY * NBPW] = {
{"allow.reserved_ports", "allow.noreserved_ports",
PR_ALLOW_RESERVED_PORTS},
{"allow.read_msgbuf", "allow.noread_msgbuf", PR_ALLOW_READ_MSGBUF},
{"allow.unprivileged_proc_debug", "allow.nounprivileged_proc_debug",
PR_ALLOW_UNPRIV_DEBUG},
};
const size_t pr_flag_allow_size = sizeof(pr_flag_allow);
#define JAIL_DEFAULT_ALLOW (PR_ALLOW_SET_HOSTNAME | PR_ALLOW_RESERVED_PORTS)
#define JAIL_DEFAULT_ALLOW (PR_ALLOW_SET_HOSTNAME | \
PR_ALLOW_RESERVED_PORTS | \
PR_ALLOW_UNPRIV_DEBUG)
#define JAIL_DEFAULT_ENFORCE_STATFS 2
#define JAIL_DEFAULT_DEVFS_RSNUM 0
static unsigned jail_default_allow = JAIL_DEFAULT_ALLOW;
@ -498,6 +502,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
int ip6s, redo_ip6;
#endif
uint64_t pr_allow, ch_allow, pr_flags, ch_flags;
uint64_t pr_allow_diff;
unsigned tallow;
char numbuf[12];
@ -1530,7 +1535,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
}
}
}
if (pr_allow & ~ppr->pr_allow) {
pr_allow_diff = pr_allow & ~ppr->pr_allow;
if (pr_allow_diff & ~PR_ALLOW_DIFFERENCES) {
error = EPERM;
goto done_deref_locked;
}
@ -3783,6 +3789,8 @@ SYSCTL_JAIL_PARAM(_allow, reserved_ports, CTLTYPE_INT | CTLFLAG_RW,
"B", "Jail may bind sockets to reserved ports");
SYSCTL_JAIL_PARAM(_allow, read_msgbuf, CTLTYPE_INT | CTLFLAG_RW,
"B", "Jail may read the kernel message buffer");
SYSCTL_JAIL_PARAM(_allow, unprivileged_proc_debug, CTLTYPE_INT | CTLFLAG_RW,
"B", "Unprivileged processes may use process debugging facilities");
SYSCTL_JAIL_PARAM_SUBNODE(allow, mount, "Jail mount/unmount permission flags");
SYSCTL_JAIL_PARAM(_allow_mount, , CTLTYPE_INT | CTLFLAG_RW,
@ -3834,10 +3842,16 @@ prison_add_allow(const char *prefix, const char *name, const char *prefix_descr,
* Find a free bit in prison0's pr_allow, failing if there are none
* (which shouldn't happen as long as we keep track of how many
* potential dynamic flags exist).
*
* Due to per-jail unprivileged process debugging support
* using pr_allow, also verify against PR_ALLOW_ALL_STATIC.
* prison0 may have unprivileged process debugging unset.
*/
for (allow_flag = 1;; allow_flag <<= 1) {
if (allow_flag == 0)
goto no_add;
if (allow_flag & PR_ALLOW_ALL_STATIC)
continue;
if ((prison0.pr_allow & allow_flag) == 0)
break;
}

View File

@ -165,6 +165,18 @@ priv_check_cred(struct ucred *cred, int priv, int flags)
goto out;
}
/*
* Allow unprivileged process debugging on a per-jail basis.
* Do this here instead of prison_priv_check(), so it can also
* apply to prison0.
*/
if (priv == PRIV_DEBUG_UNPRIV) {
if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) {
error = 0;
goto out;
}
}
/*
* Now check with MAC, if enabled, to see if a policy module grants
* privilege.

View File

@ -1629,6 +1629,37 @@ p_cansched(struct thread *td, struct proc *p)
return (0);
}
/*
* Handle getting or setting the prison's unprivileged_proc_debug
* value.
*/
static int
sysctl_unprivileged_proc_debug(SYSCTL_HANDLER_ARGS)
{
struct prison *pr;
int error, val;
val = prison_allow(req->td->td_ucred, PR_ALLOW_UNPRIV_DEBUG) != 0;
error = sysctl_handle_int(oidp, &val, 0, req);
if (error != 0 || req->newptr == NULL)
return (error);
pr = req->td->td_ucred->cr_prison;
mtx_lock(&pr->pr_mtx);
switch (val) {
case 0:
pr->pr_allow &= ~(PR_ALLOW_UNPRIV_DEBUG);
break;
case 1:
pr->pr_allow |= PR_ALLOW_UNPRIV_DEBUG;
break;
default:
error = EINVAL;
}
mtx_unlock(&pr->pr_mtx);
return (error);
}
/*
* The 'unprivileged_proc_debug' flag may be used to disable a variety of
* unprivileged inter-process debugging services, including some procfs
@ -1636,13 +1667,10 @@ p_cansched(struct thread *td, struct proc *p)
* debugging has been involved in a variety of security problems, and sites
* not requiring the service might choose to disable it when hardening
* systems.
*
* XXX: Should modifying and reading this variable require locking?
* XXX: data declarations should be together near the beginning of the file.
*/
static int unprivileged_proc_debug = 1;
SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_proc_debug, CTLFLAG_RW,
&unprivileged_proc_debug, 0,
SYSCTL_PROC(_security_bsd, OID_AUTO, unprivileged_proc_debug,
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_SECURE, 0, 0,
sysctl_unprivileged_proc_debug, "I",
"Unprivileged processes may use process debugging facilities");
/*-
@ -1660,11 +1688,8 @@ p_candebug(struct thread *td, struct proc *p)
KASSERT(td == curthread, ("%s: td not curthread", __func__));
PROC_LOCK_ASSERT(p, MA_OWNED);
if (!unprivileged_proc_debug) {
error = priv_check(td, PRIV_DEBUG_UNPRIV);
if (error)
return (error);
}
if ((error = priv_check(td, PRIV_DEBUG_UNPRIV)))
return (error);
if (td->td_proc == p)
return (0);
if ((error = prison_check(td->td_ucred, p->p_ucred)))

View File

@ -229,9 +229,16 @@ struct prison_racct {
#define PR_ALLOW_SOCKET_AF 0x00000040
#define PR_ALLOW_MLOCK 0x00000080
#define PR_ALLOW_READ_MSGBUF 0x00000100
#define PR_ALLOW_UNPRIV_DEBUG 0x00000200
#define PR_ALLOW_RESERVED_PORTS 0x00008000
#define PR_ALLOW_KMEM_ACCESS 0x00010000 /* reserved, not used yet */
#define PR_ALLOW_ALL_STATIC 0x000181ff
#define PR_ALLOW_ALL_STATIC 0x000183ff
/*
* PR_ALLOW_DIFFERENCES determines which flags are able to be
* different between the parent and child jail upon creation.
*/
#define PR_ALLOW_DIFFERENCES (PR_ALLOW_UNPRIV_DEBUG)
/*
* OSD methods

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 10, 2018
.Dd November 27, 2018
.Dt JAIL 8
.Os
.Sh NAME
@ -582,6 +582,8 @@ memory subject to
and resource limits.
.It Va allow.reserved_ports
The jail root may bind to ports lower than 1024.
.It Va allow.unprivileged_proc_debug
Unprivileged processes in the jail may use debugging facilities.
.El
.El
.Pp