Skip to content

Commit

Permalink
posix-cpu-timers: Fix rearm racing against process tick
Browse files Browse the repository at this point in the history
commit 1a3402d upstream.

Since the process wide cputime counter is started locklessly from
posix_cpu_timer_rearm(), it can be concurrently stopped by operations
on other timers from the same thread group, such as in the following
unlucky scenario:

         CPU 0                                CPU 1
         -----                                -----
                                           timer_settime(TIMER B)
   posix_cpu_timer_rearm(TIMER A)
       cpu_clock_sample_group()
           (pct->timers_active already true)

                                           handle_posix_cpu_timers()
                                               check_process_timers()
                                                   stop_process_timers()
                                                       pct->timers_active = false
       arm_timer(TIMER A)

   tick -> run_posix_cpu_timers()
       // sees !pct->timers_active, ignore
       // our TIMER A

Fix this with simply locking process wide cputime counting start and
timer arm in the same block.

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Fixes: 60f2cea ("posix-cpu-timers: Remove unnecessary locking around cpu_clock_sample_group")
Cc: stable@vger.kernel.org
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Frederic Weisbecker authored and gregkh committed Jul 28, 2021
1 parent 3efec3b commit 6e81e2c
Showing 1 changed file with 5 additions and 5 deletions.
10 changes: 5 additions & 5 deletions kernel/time/posix-cpu-timers.c
Expand Up @@ -991,6 +991,11 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
if (!p)
goto out;

/* Protect timer list r/w in arm_timer() */
sighand = lock_task_sighand(p, &flags);
if (unlikely(sighand == NULL))
goto out;

/*
* Fetch the current sample and update the timer's expiry time.
*/
Expand All @@ -1001,11 +1006,6 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)

bump_cpu_timer(timer, now);

/* Protect timer list r/w in arm_timer() */
sighand = lock_task_sighand(p, &flags);
if (unlikely(sighand == NULL))
goto out;

/*
* Now re-arm for the new expiry time.
*/
Expand Down

0 comments on commit 6e81e2c

Please sign in to comment.