git: b306be13a9c7 - releng/12.2 - MFC jail: Handle a possible race between jail_remove(2) and fork(2)
Mark Johnston
markj at FreeBSD.org
Wed Feb 24 01:42:04 UTC 2021
The branch releng/12.2 has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=b306be13a9c7ea0db8979a8a53dca93f90ec59cc
commit b306be13a9c7ea0db8979a8a53dca93f90ec59cc
Author: Jamie Gritton <jamie at FreeBSD.org>
AuthorDate: 2021-02-16 19:19:13 +0000
Commit: Mark Johnston <markj at FreeBSD.org>
CommitDate: 2021-02-24 01:41:49 +0000
MFC jail: Handle a possible race between jail_remove(2) and fork(2)
jail_remove(2) includes a loop that sends SIGKILL to all processes
in a jail, but skips processes in PRS_NEW state. Thus it is possible
the a process in mid-fork(2) during jail removal can survive the jail
being removed.
Add a prison flag PR_REMOVE, which is checked before the new process
returns. If the jail is being removed, the process will then exit.
Also check this flag in jail_attach(2) which has a similar issue.
Approved by: so
Security: CVE-2020-25581
Security: FreeBSD-SA-21:04.jail_remove
Reported by: mjg
Approved by: kib
(cherry picked from commit cc7b73065302005ebc4a19503188c8d6d5eb923d)
(cherry picked from commit f7007a7d05255a6859dea0982b1f0a6d695e8881)
---
sys/kern/kern_fork.c | 6 ++++++
sys/kern/kern_jail.c | 18 ++++++++++++++++++
sys/sys/jail.h | 1 +
3 files changed, 25 insertions(+)
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index e427164cd150..f8e134c30948 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1138,6 +1138,12 @@ fork_return(struct thread *td, struct trapframe *frame)
PROC_UNLOCK(p);
}
+ /*
+ * If the prison was killed mid-fork, die along with it.
+ */
+ if (td->td_ucred->cr_prison->pr_flags & PR_REMOVE)
+ exit1(td, 0, SIGKILL);
+
userret(td, frame);
#ifdef KTRACE
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 60cbea3c9849..b4a20b4d29e9 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -1768,6 +1768,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
}
}
pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags;
+ pr->pr_flags &= ~PR_REMOVE;
mtx_unlock(&pr->pr_mtx);
#ifdef RACCT
@@ -2306,6 +2307,12 @@ prison_remove_one(struct prison *pr)
struct proc *p;
int deuref;
+ /*
+ * Mark the prison as doomed, so it doesn't accidentally come back
+ * to life. It may still be explicitly brought back by jail_set(2).
+ */
+ pr->pr_flags |= PR_REMOVE;
+
/* If the prison was persistent, it is not anymore. */
deuref = 0;
if (pr->pr_flags & PR_PERSIST) {
@@ -2450,6 +2457,17 @@ do_jail_attach(struct thread *td, struct prison *pr)
#endif
prison_deref(oldcred->cr_prison, PD_DEREF | PD_DEUREF);
crfree(oldcred);
+
+ /*
+ * If the prison was killed while changing credentials, die along
+ * with it.
+ */
+ if (pr->pr_flags & PR_REMOVE) {
+ PROC_LOCK(p);
+ kern_psignal(p, SIGKILL);
+ PROC_UNLOCK(p);
+ }
+
return (0);
e_unlock:
diff --git a/sys/sys/jail.h b/sys/sys/jail.h
index 878b97a064a3..8baf784d6b6d 100644
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -213,6 +213,7 @@ struct prison_racct {
/* primary jail address. */
/* Internal flag bits */
+#define PR_REMOVE 0x01000000 /* In process of being removed */
#define PR_IP4 0x02000000 /* IPv4 restricted or disabled */
/* by this jail or an ancestor */
#define PR_IP6 0x04000000 /* IPv6 restricted or disabled */
More information about the dev-commits-src-all
mailing list