Index: head/sys/kern/kern_jail.c =================================================================== --- head/sys/kern/kern_jail.c +++ head/sys/kern/kern_jail.c @@ -194,10 +194,14 @@ {"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 @@ 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 @@ } } } - 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 @@ "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 @@ * 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; } Index: head/sys/kern/kern_priv.c =================================================================== --- head/sys/kern/kern_priv.c +++ head/sys/kern/kern_priv.c @@ -166,6 +166,18 @@ } /* + * 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. */ Index: head/sys/kern/kern_prot.c =================================================================== --- head/sys/kern/kern_prot.c +++ head/sys/kern/kern_prot.c @@ -1630,19 +1630,47 @@ } /* + * 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 * functionality, ptrace(), and ktrace(). In the past, inter-process * 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 @@ 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))) Index: head/sys/sys/jail.h =================================================================== --- head/sys/sys/jail.h +++ head/sys/sys/jail.h @@ -229,9 +229,16 @@ #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 Index: head/usr.sbin/jail/jail.8 =================================================================== --- head/usr.sbin/jail/jail.8 +++ head/usr.sbin/jail/jail.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 10, 2018 +.Dd November 27, 2018 .Dt JAIL 8 .Os .Sh NAME @@ -582,6 +582,8 @@ 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