@@ -455,6 +455,109 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
455455 trigger_base_recalc_expires (timer , p );
456456}
457457
458+ /*
459+ * Lookup the task via timer->it.cpu.pid and attempt to lock the task's sighand.
460+ *
461+ * This can race with the reaping of the task:
462+ *
463+ * CPU0 CPU1
464+ *
465+ * // Finds task
466+ * p = pid_task(pid, pid_type); __exit_signal(p)
467+ * lock(p, sighand);
468+ * posix_cpu_timers*_exit();
469+ * sighand = lock_task_sighand(p); unhash_task(p);
470+ * p->sighand = NULL;
471+ * unlock(sighand);
472+ *
473+ * In this case sighand is NULL, which means the task and the associated timer
474+ * queue cannot be longer accessed safely.
475+ *
476+ * __exit_signal() invokes posix_cpu_timers_exit() and if the thread group is
477+ * dead it also invokes posix_cpu_timers_group_exit(). These functions delete
478+ * all pending timers from the related timer queues. The POSIX timers (k_itimer)
479+ * themself are still accessible, but not longer connected to the task.
480+ *
481+ * exec() works slightly differently. The task which exec()'s terminates all
482+ * other threads in the thread group and runs __exit_signal() on them. As the
483+ * thread group is not dead they only clean up the per task timers via
484+ * posix_cpu_timers_exit().
485+ *
486+ * As the TGID on exec() stays the same per process timers stay queued, if they
487+ * are armed. This works without a problem when exec() is done by the thread
488+ * group leader. If a non-leader thread exec()'s this can end up in the
489+ * following scenario:
490+ *
491+ * CPU0 CPU1
492+ * // Returns old leader
493+ * p = pid_task(pid, pid_type); de_thread()
494+ * switch_leader()
495+ * release_task(old leader)
496+ * __exit_signal()
497+ * old_leader->sighand = NULL;
498+ * // Returns NULL
499+ * sighand = lock_task_sighand(p)
500+ *
501+ * That's problematic for several functions:
502+ *
503+ * - posix_cpu_timer_del(): If the timer is still enqueued on the task the
504+ * underlying k_itimer will be freed which results in a UAF in
505+ * run_posix_cpu_timers() or on timerqueue related add/delete operations.
506+ * If the timer is not enqueued, the failure is harmless
507+ *
508+ * - posix_cpu_timer_set(): Independent of the enqueued state that results in a
509+ * transient failure which is user space visible (-ESRCH) for regular posix
510+ * timers. But for the use case in do_cpu_nanosleep() it's the same UAF
511+ * problem just that the timer is allocated on the stack.
512+ *
513+ * - posix_cpu_timer_rearm(): Timer is not enqueued at that point, but this
514+ * silently ignores the rearm request, which is a functional problem as the
515+ * timer wont expire anymore.
516+ */
517+ static struct task_struct * timer_lock_sighand (struct k_itimer * timer , unsigned long * flags )
518+ {
519+ enum pid_type type = clock_pid_type (timer -> it_clock );
520+ struct cpu_timer * ctmr = & timer -> it .cpu ;
521+
522+ guard (rcu )();
523+
524+ for (;;) {
525+ struct task_struct * t = pid_task (timer -> it .cpu .pid , type );
526+
527+ /* Fail if the task cannot be found. */
528+ if (!t )
529+ break ;
530+
531+ /* Try to lock the task's sighand */
532+ if (lock_task_sighand (t , flags ))
533+ return t ;
534+
535+ /*
536+ * The next PID lookup might either fail or return the new
537+ * leader. This is correct for both exit() and exec().
538+ */
539+ }
540+
541+ /*
542+ * If the timer is still enqueued, warn. There is nothing safe to do
543+ * here as there might be two timers in there which are removed in
544+ * parallel and that will cause more damage than good. This should never
545+ * happen!
546+ *
547+ * Ensure that the stores to the timer and timerqueue are visible:
548+ *
549+ * __exit_signal()
550+ * posix_cpu_timers*_exit()
551+ * write_seqlock(seqlock)
552+ * smp_wmb(); <-------
553+ * __unhash_process() | !pid_task()
554+ * ----> smp_rmb();
555+ * WARN_ON_ONCE(...)
556+ */
557+ smp_rmb ();
558+ WARN_ON_ONCE (ctmr -> head || timerqueue_node_queued (& ctmr -> node ));
559+ return NULL ;
560+ }
458561
459562/*
460563 * Clean up a CPU-clock timer that is about to be destroyed.
@@ -464,29 +567,13 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
464567 */
465568static int posix_cpu_timer_del (struct k_itimer * timer )
466569{
467- struct cpu_timer * ctmr = & timer -> it .cpu ;
468- struct sighand_struct * sighand ;
469570 struct task_struct * p ;
470571 unsigned long flags ;
471572 int ret = 0 ;
472573
473- rcu_read_lock ();
474- p = cpu_timer_task_rcu (timer );
475- if (!p )
476- goto out ;
574+ p = timer_lock_sighand (timer , & flags );
477575
478- /*
479- * Protect against sighand release/switch in exit/exec and process/
480- * thread timer list entry concurrent read/writes.
481- */
482- sighand = lock_task_sighand (p , & flags );
483- if (unlikely (sighand == NULL )) {
484- /*
485- * This raced with the reaping of the task. The exit cleanup
486- * should have removed this timer from the timer queue.
487- */
488- WARN_ON_ONCE (ctmr -> head || timerqueue_node_queued (& ctmr -> node ));
489- } else {
576+ if (likely (p )) {
490577 if (timer -> it .cpu .firing )
491578 ret = TIMER_RETRY ;
492579 else
@@ -495,10 +582,8 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
495582 unlock_task_sighand (p , & flags );
496583 }
497584
498- out :
499- rcu_read_unlock ();
500585 if (!ret )
501- put_pid (ctmr -> pid );
586+ put_pid (timer -> it . cpu . pid );
502587
503588 return ret ;
504589}
@@ -620,42 +705,24 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
620705 clockid_t clkid = CPUCLOCK_WHICH (timer -> it_clock );
621706 u64 old_expires , new_expires , old_incr , val ;
622707 struct cpu_timer * ctmr = & timer -> it .cpu ;
623- struct sighand_struct * sighand ;
624708 struct task_struct * p ;
625709 unsigned long flags ;
626710 int ret = 0 ;
627711
628- rcu_read_lock ();
629- p = cpu_timer_task_rcu (timer );
630- if (!p ) {
631- /*
632- * If p has just been reaped, we can no
633- * longer get any information about it at all.
634- */
635- rcu_read_unlock ();
712+ p = timer_lock_sighand (timer , & flags );
713+ /*
714+ * If p has just been reaped, we can no longer get any information about
715+ * it at all.
716+ */
717+ if (!p )
636718 return - ESRCH ;
637- }
638719
639720 /*
640721 * Use the to_ktime conversion because that clamps the maximum
641722 * value to KTIME_MAX and avoid multiplication overflows.
642723 */
643724 new_expires = ktime_to_ns (timespec64_to_ktime (new -> it_value ));
644725
645- /*
646- * Protect against sighand release/switch in exit/exec and p->cpu_timers
647- * and p->signal->cpu_timers read/write in arm_timer()
648- */
649- sighand = lock_task_sighand (p , & flags );
650- /*
651- * If p has just been reaped, we can no
652- * longer get any information about it at all.
653- */
654- if (unlikely (sighand == NULL )) {
655- rcu_read_unlock ();
656- return - ESRCH ;
657- }
658-
659726 /*
660727 * Disarm any old timer after extracting its expiry time.
661728 */
@@ -704,6 +771,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
704771 old -> it_value .tv_sec = 0 ;
705772 }
706773 }
774+ old -> it_interval = ns_to_timespec64 (old_incr );
707775 }
708776
709777 if (unlikely (ret )) {
@@ -714,7 +782,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
714782 * it as an overrun (thanks to bump_cpu_timer above).
715783 */
716784 unlock_task_sighand (p , & flags );
717- goto out ;
785+ return ret ;
718786 }
719787
720788 if (new_expires != 0 && !(timer_flags & TIMER_ABSTIME )) {
@@ -727,11 +795,11 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
727795 * arm the timer (we'll just fake it for timer_gettime).
728796 */
729797 cpu_timer_setexpires (ctmr , new_expires );
730- if (new_expires != 0 && val < new_expires ) {
798+ if (new_expires != 0 && val < new_expires )
731799 arm_timer (timer , p );
732- }
800+ else
801+ trigger_base_recalc_expires (timer , p );
733802
734- unlock_task_sighand (p , & flags );
735803 /*
736804 * Install the new reload setting, and
737805 * set up the signal and overrun bookkeeping.
@@ -748,35 +816,18 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
748816 timer -> it_overrun_last = 0 ;
749817 timer -> it_overrun = -1 ;
750818
751- if (val >= new_expires ) {
752- if (new_expires != 0 ) {
753- /*
754- * The designated time already passed, so we notify
755- * immediately, even if the thread never runs to
756- * accumulate more time on this clock.
757- */
758- cpu_timer_fire (timer );
759- }
819+ unlock_task_sighand (p , & flags );
760820
821+ if (new_expires && val >= new_expires ) {
761822 /*
762- * Make sure we don't keep around the process wide cputime
763- * counter or the tick dependency if they are not necessary.
823+ * The designated time already passed, so we notify immediately,
824+ * even if the thread never runs to accumulate more time on this
825+ * clock.
764826 */
765- sighand = lock_task_sighand (p , & flags );
766- if (!sighand )
767- goto out ;
768-
769- if (!cpu_timer_queued (ctmr ))
770- trigger_base_recalc_expires (timer , p );
771-
772- unlock_task_sighand (p , & flags );
827+ cpu_timer_fire (timer );
773828 }
774- out :
775- rcu_read_unlock ();
776- if (old )
777- old -> it_interval = ns_to_timespec64 (old_incr );
778829
779- return ret ;
830+ return 0 ;
780831}
781832
782833static void posix_cpu_timer_get (struct k_itimer * timer , struct itimerspec64 * itp )
@@ -1042,19 +1093,12 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
10421093{
10431094 clockid_t clkid = CPUCLOCK_WHICH (timer -> it_clock );
10441095 struct task_struct * p ;
1045- struct sighand_struct * sighand ;
10461096 unsigned long flags ;
10471097 u64 now ;
10481098
1049- rcu_read_lock ();
1050- p = cpu_timer_task_rcu (timer );
1051- if (!p )
1052- goto out ;
1053-
1054- /* Protect timer list r/w in arm_timer() */
1055- sighand = lock_task_sighand (p , & flags );
1056- if (unlikely (sighand == NULL ))
1057- goto out ;
1099+ p = timer_lock_sighand (timer , & flags );
1100+ if (unlikely (!p ))
1101+ return ;
10581102
10591103 /*
10601104 * Fetch the current sample and update the timer's expiry time.
@@ -1071,8 +1115,6 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
10711115 */
10721116 arm_timer (timer , p );
10731117 unlock_task_sighand (p , & flags );
1074- out :
1075- rcu_read_unlock ();
10761118}
10771119
10781120/**
0 commit comments