@@ -462,6 +462,109 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
462462 trigger_base_recalc_expires (timer , p );
463463}
464464
465+ /*
466+ * Lookup the task via timer->it.cpu.pid and attempt to lock the task's sighand.
467+ *
468+ * This can race with the reaping of the task:
469+ *
470+ * CPU0 CPU1
471+ *
472+ * // Finds task
473+ * p = pid_task(pid, pid_type); __exit_signal(p)
474+ * lock(p, sighand);
475+ * posix_cpu_timers*_exit();
476+ * sighand = lock_task_sighand(p); unhash_task(p);
477+ * p->sighand = NULL;
478+ * unlock(sighand);
479+ *
480+ * In this case sighand is NULL, which means the task and the associated timer
481+ * queue cannot be longer accessed safely.
482+ *
483+ * __exit_signal() invokes posix_cpu_timers_exit() and if the thread group is
484+ * dead it also invokes posix_cpu_timers_group_exit(). These functions delete
485+ * all pending timers from the related timer queues. The POSIX timers (k_itimer)
486+ * themself are still accessible, but not longer connected to the task.
487+ *
488+ * exec() works slightly differently. The task which exec()'s terminates all
489+ * other threads in the thread group and runs __exit_signal() on them. As the
490+ * thread group is not dead they only clean up the per task timers via
491+ * posix_cpu_timers_exit().
492+ *
493+ * As the TGID on exec() stays the same per process timers stay queued, if they
494+ * are armed. This works without a problem when exec() is done by the thread
495+ * group leader. If a non-leader thread exec()'s this can end up in the
496+ * following scenario:
497+ *
498+ * CPU0 CPU1
499+ * // Returns old leader
500+ * p = pid_task(pid, pid_type); de_thread()
501+ * switch_leader()
502+ * release_task(old leader)
503+ * __exit_signal()
504+ * old_leader->sighand = NULL;
505+ * // Returns NULL
506+ * sighand = lock_task_sighand(p)
507+ *
508+ * That's problematic for several functions:
509+ *
510+ * - posix_cpu_timer_del(): If the timer is still enqueued on the task the
511+ * underlying k_itimer will be freed which results in a UAF in
512+ * run_posix_cpu_timers() or on timerqueue related add/delete operations.
513+ * If the timer is not enqueued, the failure is harmless
514+ *
515+ * - posix_cpu_timer_set(): Independent of the enqueued state that results in a
516+ * transient failure which is user space visible (-ESRCH) for regular posix
517+ * timers. But for the use case in do_cpu_nanosleep() it's the same UAF
518+ * problem just that the timer is allocated on the stack.
519+ *
520+ * - posix_cpu_timer_rearm(): Timer is not enqueued at that point, but this
521+ * silently ignores the rearm request, which is a functional problem as the
522+ * timer wont expire anymore.
523+ */
524+ static struct task_struct * timer_lock_sighand (struct k_itimer * timer , unsigned long * flags )
525+ {
526+ enum pid_type type = clock_pid_type (timer -> it_clock );
527+ struct cpu_timer * ctmr = & timer -> it .cpu ;
528+
529+ guard (rcu )();
530+
531+ for (;;) {
532+ struct task_struct * t = pid_task (timer -> it .cpu .pid , type );
533+
534+ /* Fail if the task cannot be found. */
535+ if (!t )
536+ break ;
537+
538+ /* Try to lock the task's sighand */
539+ if (lock_task_sighand (t , flags ))
540+ return t ;
541+
542+ /*
543+ * The next PID lookup might either fail or return the new
544+ * leader. This is correct for both exit() and exec().
545+ */
546+ }
547+
548+ /*
549+ * If the timer is still enqueued, warn. There is nothing safe to do
550+ * here as there might be two timers in there which are removed in
551+ * parallel and that will cause more damage than good. This should never
552+ * happen!
553+ *
554+ * Ensure that the stores to the timer and timerqueue are visible:
555+ *
556+ * __exit_signal()
557+ * posix_cpu_timers*_exit()
558+ * write_seqlock(seqlock)
559+ * smp_wmb(); <-------
560+ * __unhash_process() | !pid_task()
561+ * ----> smp_rmb();
562+ * WARN_ON_ONCE(...)
563+ */
564+ smp_rmb ();
565+ WARN_ON_ONCE (ctmr -> head || timerqueue_node_queued (& ctmr -> node ));
566+ return NULL ;
567+ }
465568
466569/*
467570 * Clean up a CPU-clock timer that is about to be destroyed.
@@ -471,29 +574,13 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
471574 */
472575static int posix_cpu_timer_del (struct k_itimer * timer )
473576{
474- struct cpu_timer * ctmr = & timer -> it .cpu ;
475- struct sighand_struct * sighand ;
476577 struct task_struct * p ;
477578 unsigned long flags ;
478579 int ret = 0 ;
479580
480- rcu_read_lock ();
481- p = cpu_timer_task_rcu (timer );
482- if (!p )
483- goto out ;
581+ p = timer_lock_sighand (timer , & flags );
484582
485- /*
486- * Protect against sighand release/switch in exit/exec and process/
487- * thread timer list entry concurrent read/writes.
488- */
489- sighand = lock_task_sighand (p , & flags );
490- if (unlikely (sighand == NULL )) {
491- /*
492- * This raced with the reaping of the task. The exit cleanup
493- * should have removed this timer from the timer queue.
494- */
495- WARN_ON_ONCE (ctmr -> head || timerqueue_node_queued (& ctmr -> node ));
496- } else {
583+ if (likely (p )) {
497584 if (timer -> it .cpu .firing )
498585 ret = TIMER_RETRY ;
499586 else
@@ -502,10 +589,8 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
502589 unlock_task_sighand (p , & flags );
503590 }
504591
505- out :
506- rcu_read_unlock ();
507592 if (!ret )
508- put_pid (ctmr -> pid );
593+ put_pid (timer -> it . cpu . pid );
509594
510595 return ret ;
511596}
@@ -627,42 +712,24 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
627712 clockid_t clkid = CPUCLOCK_WHICH (timer -> it_clock );
628713 u64 old_expires , new_expires , old_incr , val ;
629714 struct cpu_timer * ctmr = & timer -> it .cpu ;
630- struct sighand_struct * sighand ;
631715 struct task_struct * p ;
632716 unsigned long flags ;
633717 int ret = 0 ;
634718
635- rcu_read_lock ();
636- p = cpu_timer_task_rcu (timer );
637- if (!p ) {
638- /*
639- * If p has just been reaped, we can no
640- * longer get any information about it at all.
641- */
642- rcu_read_unlock ();
719+ p = timer_lock_sighand (timer , & flags );
720+ /*
721+ * If p has just been reaped, we can no longer get any information about
722+ * it at all.
723+ */
724+ if (!p )
643725 return - ESRCH ;
644- }
645726
646727 /*
647728 * Use the to_ktime conversion because that clamps the maximum
648729 * value to KTIME_MAX and avoid multiplication overflows.
649730 */
650731 new_expires = ktime_to_ns (timespec64_to_ktime (new -> it_value ));
651732
652- /*
653- * Protect against sighand release/switch in exit/exec and p->cpu_timers
654- * and p->signal->cpu_timers read/write in arm_timer()
655- */
656- sighand = lock_task_sighand (p , & flags );
657- /*
658- * If p has just been reaped, we can no
659- * longer get any information about it at all.
660- */
661- if (unlikely (sighand == NULL )) {
662- rcu_read_unlock ();
663- return - ESRCH ;
664- }
665-
666733 /*
667734 * Disarm any old timer after extracting its expiry time.
668735 */
@@ -711,6 +778,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
711778 old -> it_value .tv_sec = 0 ;
712779 }
713780 }
781+ old -> it_interval = ns_to_timespec64 (old_incr );
714782 }
715783
716784 if (unlikely (ret )) {
@@ -721,7 +789,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
721789 * it as an overrun (thanks to bump_cpu_timer above).
722790 */
723791 unlock_task_sighand (p , & flags );
724- goto out ;
792+ return ret ;
725793 }
726794
727795 if (new_expires != 0 && !(timer_flags & TIMER_ABSTIME )) {
@@ -734,11 +802,11 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
734802 * arm the timer (we'll just fake it for timer_gettime).
735803 */
736804 cpu_timer_setexpires (ctmr , new_expires );
737- if (new_expires != 0 && val < new_expires ) {
805+ if (new_expires != 0 && val < new_expires )
738806 arm_timer (timer , p );
739- }
807+ else
808+ trigger_base_recalc_expires (timer , p );
740809
741- unlock_task_sighand (p , & flags );
742810 /*
743811 * Install the new reload setting, and
744812 * set up the signal and overrun bookkeeping.
@@ -755,35 +823,18 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
755823 timer -> it_overrun_last = 0 ;
756824 timer -> it_overrun = -1 ;
757825
758- if (val >= new_expires ) {
759- if (new_expires != 0 ) {
760- /*
761- * The designated time already passed, so we notify
762- * immediately, even if the thread never runs to
763- * accumulate more time on this clock.
764- */
765- cpu_timer_fire (timer );
766- }
826+ unlock_task_sighand (p , & flags );
767827
828+ if (new_expires && val >= new_expires ) {
768829 /*
769- * Make sure we don't keep around the process wide cputime
770- * counter or the tick dependency if they are not necessary.
830+ * The designated time already passed, so we notify immediately,
831+ * even if the thread never runs to accumulate more time on this
832+ * clock.
771833 */
772- sighand = lock_task_sighand (p , & flags );
773- if (!sighand )
774- goto out ;
775-
776- if (!cpu_timer_queued (ctmr ))
777- trigger_base_recalc_expires (timer , p );
778-
779- unlock_task_sighand (p , & flags );
834+ cpu_timer_fire (timer );
780835 }
781- out :
782- rcu_read_unlock ();
783- if (old )
784- old -> it_interval = ns_to_timespec64 (old_incr );
785836
786- return ret ;
837+ return 0 ;
787838}
788839
789840static void posix_cpu_timer_get (struct k_itimer * timer , struct itimerspec64 * itp )
@@ -1049,19 +1100,12 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
10491100{
10501101 clockid_t clkid = CPUCLOCK_WHICH (timer -> it_clock );
10511102 struct task_struct * p ;
1052- struct sighand_struct * sighand ;
10531103 unsigned long flags ;
10541104 u64 now ;
10551105
1056- rcu_read_lock ();
1057- p = cpu_timer_task_rcu (timer );
1058- if (!p )
1059- goto out ;
1060-
1061- /* Protect timer list r/w in arm_timer() */
1062- sighand = lock_task_sighand (p , & flags );
1063- if (unlikely (sighand == NULL ))
1064- goto out ;
1106+ p = timer_lock_sighand (timer , & flags );
1107+ if (unlikely (!p ))
1108+ return ;
10651109
10661110 /*
10671111 * Fetch the current sample and update the timer's expiry time.
@@ -1078,8 +1122,6 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
10781122 */
10791123 arm_timer (timer , p );
10801124 unlock_task_sighand (p , & flags );
1081- out :
1082- rcu_read_unlock ();
10831125}
10841126
10851127/**
0 commit comments