git: a6268f89d58c - main - proc: Disallow re-enabling of process itimers during exit

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 31 Mar 2025 09:06:36 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=a6268f89d58c1962d2372a664a35eaecbf367fbb

commit a6268f89d58c1962d2372a664a35eaecbf367fbb
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-03-31 01:22:14 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-03-31 09:01:09 +0000

    proc: Disallow re-enabling of process itimers during exit
    
    During process exit, it's possible for the exiting thread to send a
    signal to its process, via killjobc().  This happens after the itimer is
    drained.  If itimers are stopped, i.e., P2_ITSTOPPED is set, then
    itimer_proc_continue() will resume the callout after it has been
    drained.
    
    Fix the problem by simply clearing P2_ITSTOPPED as part of the drain.
    Then, a signal received after that point will not re-enable the callout.
    For good measure, also make sure that we don't reset the itimer callout
    in an exiting process.
    
    Reported by:    syzkaller
    Reviewed by:    kib
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D49529
---
 sys/kern/kern_exit.c | 1 +
 sys/kern/kern_time.c | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index a67d6b422964..54e3044ab093 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -375,6 +375,7 @@ exit1(struct thread *td, int rval, int signo)
 	 * Stop the real interval timer.  If the handler is currently
 	 * executing, prevent it from rearming itself and let it finish.
 	 */
+	p->p_flag2 &= ~P2_ITSTOPPED;
 	if (timevalisset(&p->p_realtimer.it_value) &&
 	    callout_stop(&p->p_itcallout) == 0) {
 		timevalclear(&p->p_realtimer.it_interval);
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index c94ae49b6923..d7dc78366292 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -884,6 +884,8 @@ realitexpire_reset_callout(struct proc *p, sbintime_t *isbtp)
 {
 	sbintime_t prec;
 
+	if ((p->p_flag & P_WEXIT) != 0)
+		return;
 	prec = isbtp == NULL ? tvtosbt(p->p_realtimer.it_interval) : *isbtp;
 	callout_reset_sbt(&p->p_itcallout, tvtosbt(p->p_realtimer.it_value),
 	    prec >> tc_precexp, realitexpire, p, C_ABSOLUTE);