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: 57b8015e07 ("posix-timers: Show sigevent info in proc file")
Signed-off-by: Andrei Vagin <avagin@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Andrei Vagin 2026-08-16 16:12:15 +00:00 committed by Andrew Morton
parent 51e766bcd3
commit 0a27f79503

View File

@ -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;