From 8d030d0c19aed7d172b1cec6e459579cdc16052f Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 16 Aug 2026 16:12:15 +0000 Subject: proc: report SIGEV_NONE in /proc/pid/timers if target task has died When a posix timer is created targeting a specific thread (using SIGEV_SIGNAL | SIGEV_THREAD_ID), it takes a reference to the target struct pid in timer->it_pid. If the target thread subsequently terminates, its numeric tid is freed and can be recycled for an unrelated task. However, the timer holds its reference to the original struct pid. show_timer() in /proc/[pid]/timers previously called pid_nr_ns() directly on timer->it_pid without checking whether any task remained attached to that struct pid. As a result: 1. It reported the stale tid, which could mistakenly refer to a recycled pid. 2. In the kernel, expired signals for dead target threads are dropped by posixtimer_send_sigqueue() because posixtimer_get_target() returns NULL, so the timer functionally acts as SIGEV_NONE. 3. Checkpoint/restore tools (CRIU) parsing /proc/[pid]/timers would try to restore a timer with SIGEV_SIGNAL | SIGEV_THREAD_ID targeting a non-existent or unrelated thread. Check pid_has_task(timer->it_pid, timer->it_pid_type) in show_timer(). If the target task has died, override notify to SIGEV_NONE and report PID 0 (e.g., 'notify: none/pid.0'). Link: https://lore.kernel.org/20260816161216.984580-1-avagin@google.com Fixes: 57b8015e07a7 ("posix-timers: Show sigevent info in proc file") Signed-off-by: Andrei Vagin Reviewed-by: Pavel Tikhomirov Cc: Thomas Gleixner Signed-off-by: Andrew Morton --- fs/proc/base.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 6a39de424f62..1455de58e53c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2519,17 +2519,23 @@ static int show_timer(struct seq_file *m, void *v) struct k_itimer *timer = hlist_entry((struct hlist_node *)v, struct k_itimer, list); struct timers_private *tp = m->private; int notify = timer->it_sigev_notify; + pid_t nr = 0; guard(spinlock_irq)(&timer->it_lock); if (!posixtimer_valid(timer)) return 0; + if (timer->it_pid && pid_has_task(timer->it_pid, timer->it_pid_type)) + nr = pid_nr_ns(timer->it_pid, tp->ns); + else + notify = SIGEV_NONE; + seq_printf(m, "ID: %d\n", timer->it_id); seq_printf(m, "signal: %d/%px\n", timer->sigq.info.si_signo, timer->sigq.info.si_value.sival_ptr); seq_printf(m, "notify: %s/%s.%d\n", nstr[notify & ~SIGEV_THREAD_ID], (notify & SIGEV_THREAD_ID) ? "tid" : "pid", - pid_nr_ns(timer->it_pid, tp->ns)); + nr); seq_printf(m, "ClockID: %d\n", timer->it_clock); return 0; -- cgit v1.2.3