aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_jail.c10
-rw-r--r--sys/kern/kern_prot.c56
2 files changed, 66 insertions, 0 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 14e6e735f8e7..7c9a15ae18f3 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -235,6 +235,9 @@ static struct bool_flags pr_flag_allow[NBBY * NBPW] = {
{"allow.adjtime", "allow.noadjtime", PR_ALLOW_ADJTIME},
{"allow.settime", "allow.nosettime", PR_ALLOW_SETTIME},
{"allow.routing", "allow.norouting", PR_ALLOW_ROUTING},
+ {"allow.unprivileged_parent_tampering",
+ "allow.nounprivileged_parent_tampering",
+ PR_ALLOW_UNPRIV_PARENT_TAMPER},
};
static unsigned pr_allow_all = PR_ALLOW_ALL_STATIC;
const size_t pr_flag_allow_size = sizeof(pr_flag_allow);
@@ -4009,6 +4012,7 @@ prison_priv_check(struct ucred *cred, int priv)
case PRIV_DEBUG_DIFFCRED:
case PRIV_DEBUG_SUGID:
case PRIV_DEBUG_UNPRIV:
+ case PRIV_DEBUG_DIFFJAIL:
/*
* Allow jail to set various resource limits and login
@@ -4046,8 +4050,10 @@ prison_priv_check(struct ucred *cred, int priv)
*/
case PRIV_SCHED_DIFFCRED:
case PRIV_SCHED_CPUSET:
+ case PRIV_SCHED_DIFFJAIL:
case PRIV_SIGNAL_DIFFCRED:
case PRIV_SIGNAL_SUGID:
+ case PRIV_SIGNAL_DIFFJAIL:
/*
* Allow jailed processes to write to sysctls marked as jail
@@ -4691,6 +4697,10 @@ 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(_allow, unprivileged_parent_tampering,
+ CTLTYPE_INT | CTLFLAG_RW, "B",
+ "Unprivileged parent jail processes may tamper with same-uid processes"
+ " (signal/debug/cpuset)");
SYSCTL_JAIL_PARAM(_allow, suser, CTLTYPE_INT | CTLFLAG_RW,
"B", "Processes in jail with uid 0 have privilege");
#ifdef VIMAGE
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index bbb622547598..2cd5b7069023 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -1914,6 +1914,38 @@ cr_canseejailproc(struct ucred *u1, struct ucred *u2)
}
/*
+ * Determine if u1 can tamper with the subject specified by u2, if they are in
+ * different jails and 'unprivileged_parent_tampering' jail policy allows it.
+ *
+ * May be called if u1 and u2 are in the same jail, but it is expected that the
+ * caller has already done a prison_check() prior to calling it.
+ *
+ * Returns: 0 for permitted, EPERM otherwise
+ */
+static int
+cr_can_tamper_with_subjail(struct ucred *u1, struct ucred *u2, int priv)
+{
+
+ MPASS(prison_check(u1, u2) == 0);
+ if (u1->cr_prison == u2->cr_prison)
+ return (0);
+
+ if (priv_check_cred(u1, priv) == 0)
+ return (0);
+
+ /*
+ * Jails do not maintain a distinct UID space, so process visibility is
+ * all that would control an unprivileged process' ability to tamper
+ * with a process in a subjail by default if we did not have the
+ * allow.unprivileged_parent_tampering knob to restrict it by default.
+ */
+ if (prison_allow(u2, PR_ALLOW_UNPRIV_PARENT_TAMPER))
+ return (0);
+
+ return (EPERM);
+}
+
+/*
* Helper for cr_cansee*() functions to abide by system-wide security.bsd.see_*
* policies. Determines if u1 "can see" u2 according to these policies.
* Returns: 0 for permitted, ESRCH otherwise
@@ -2062,6 +2094,19 @@ cr_cansignal(struct ucred *cred, struct proc *proc, int signum)
return (error);
}
+ /*
+ * At this point, the target may be in a different jail than the
+ * subject -- the subject must be in a parent jail to the target,
+ * whether it is prison0 or a subordinate of prison0 that has
+ * children. Additional privileges are required to allow this, as
+ * whether the creds are truly equivalent or not must be determined on
+ * a case-by-case basis.
+ */
+ error = cr_can_tamper_with_subjail(cred, proc->p_ucred,
+ PRIV_SIGNAL_DIFFJAIL);
+ if (error)
+ return (error);
+
return (0);
}
@@ -2138,6 +2183,12 @@ p_cansched(struct thread *td, struct proc *p)
if (error)
return (error);
}
+
+ error = cr_can_tamper_with_subjail(td->td_ucred, p->p_ucred,
+ PRIV_SCHED_DIFFJAIL);
+ if (error)
+ return (error);
+
return (0);
}
@@ -2258,6 +2309,11 @@ p_candebug(struct thread *td, struct proc *p)
return (error);
}
+ error = cr_can_tamper_with_subjail(td->td_ucred, p->p_ucred,
+ PRIV_DEBUG_DIFFJAIL);
+ if (error)
+ return (error);
+
/* Can't trace init when securelevel > 0. */
if (p == initproc) {
error = securelevel_gt(td->td_ucred, 0);