git: b31917186146 - main - setitimer: Fix exit race
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 23 Mar 2022 16:47:12 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=b319171861464f6c445905e7649cb43bf9bc78be
commit b319171861464f6c445905e7649cb43bf9bc78be
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2022-03-23 16:36:12 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2022-03-23 16:36:12 +0000
setitimer: Fix exit race
We use the p_itcallout callout, interlocked by the proc lock, to
schedule timeouts for the setitimer(2) system call. When a process
exits, the callout must be stopped before the process struct is
recycled.
Currently we attempt to stop the callout in exit1() with the call
_callout_stop_safe(&p->p_itcallout, CS_EXECUTING). If this call returns
0, then we sleep in order to drain the callout. However, this happens
only if the callout is not scheduled at all. If the callout thread is
blocked on the proc lock, then exit1() will not block and the callout
may execute after the process has fully exited, typically resulting in a
panic.
I cannot see a reason to use the CS_EXECUTING flag here. Instead, use
the regular callout_stop()/callout_drain() dance to halt the callout.
Reported by: ler
Tested by: ler, pho
MFC after: 1 month
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D34625
---
sys/kern/kern_exit.c | 11 +++++------
sys/kern/kern_time.c | 2 --
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 6d1cd5705f30..7215aed60c83 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -369,15 +369,14 @@ exit1(struct thread *td, int rval, int signo)
* executing, prevent it from rearming itself and let it finish.
*/
if (timevalisset(&p->p_realtimer.it_value) &&
- _callout_stop_safe(&p->p_itcallout, CS_EXECUTING, NULL) == 0) {
+ callout_stop(&p->p_itcallout) == 0) {
timevalclear(&p->p_realtimer.it_interval);
- msleep(&p->p_itcallout, &p->p_mtx, PWAIT, "ritwait", 0);
- KASSERT(!timevalisset(&p->p_realtimer.it_value),
- ("realtime timer is still armed"));
+ PROC_UNLOCK(p);
+ callout_drain(&p->p_itcallout);
+ } else {
+ PROC_UNLOCK(p);
}
- PROC_UNLOCK(p);
-
if (p->p_sysent->sv_onexit != NULL)
p->p_sysent->sv_onexit(p);
seltdfini(td);
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 194a23fdc9e8..f052c4b6d698 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -950,8 +950,6 @@ realitexpire(void *arg)
kern_psignal(p, SIGALRM);
if (!timevalisset(&p->p_realtimer.it_interval)) {
timevalclear(&p->p_realtimer.it_value);
- if (p->p_flag & P_WEXIT)
- wakeup(&p->p_itcallout);
return;
}