Skip to content
  • Eric W. Biederman's avatar
    signal: Only reschedule timers on signals timers have sent · 57db7e4a
    Eric W. Biederman authored
    
    
    Thomas Gleixner  wrote:
    > The CRIU support added a 'feature' which allows a user space task to send
    > arbitrary (kernel) signals to itself. The changelog says:
    >
    >   The kernel prevents sending of siginfo with positive si_code, because
    >   these codes are reserved for kernel.  I think we can allow a task to
    >   send such a siginfo to itself.  This operation should not be dangerous.
    >
    > Quite contrary to that claim, it turns out that it is outright dangerous
    > for signals with info->si_code == SI_TIMER. The following code sequence in
    > a user space task allows to crash the kernel:
    >
    >    id = timer_create(CLOCK_XXX, ..... signo = SIGX);
    >    timer_set(id, ....);
    >    info->si_signo = SIGX;
    >    info->si_code = SI_TIMER:
    >    info->_sifields._timer._tid = id;
    >    info->_sifields._timer._sys_private = 2;
    >    rt_[tg]sigqueueinfo(..., SIGX, info);
    >    sigemptyset(&sigset);
    >    sigaddset(&sigset, SIGX);
    >    rt_sigtimedwait(sigset, info);
    >
    > For timers based on CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID this
    > results in a kernel crash because sigwait() dequeues the signal and the
    > dequeue code observes:
    >
    >   info->si_code == SI_TIMER && info->_sifields._timer._sys_private != 0
    >
    > which triggers the following callchain:
    >
    >  do_schedule_next_timer() -> posix_cpu_timer_schedule() -> arm_timer()
    >
    > arm_timer() executes a list_add() on the timer, which is already armed via
    > the timer_set() syscall. That's a double list add which corrupts the posix
    > cpu timer list. As a consequence the kernel crashes on the next operation
    > touching the posix cpu timer list.
    >
    > Posix clocks which are internally implemented based on hrtimers are not
    > affected by this because hrtimer_start() can handle already armed timers
    > nicely, but it's a reliable way to trigger the WARN_ON() in
    > hrtimer_forward(), which complains about calling that function on an
    > already armed timer.
    
    This problem has existed since the posix timer code was merged into
    2.5.63. A few releases earlier in 2.5.60 ptrace gained the ability to
    inject not just a signal (which linux has supported since 1.0) but the
    full siginfo of a signal.
    
    The core problem is that the code will reschedule in response to
    signals getting dequeued not just for signals the timers sent but
    for other signals that happen to a si_code of SI_TIMER.
    
    Avoid this confusion by testing to see if the queued signal was
    preallocated as all timer signals are preallocated, and so far
    only the timer code preallocates signals.
    
    Move the check for if a timer needs to be rescheduled up into
    collect_signal where the preallocation check must be performed,
    and pass the result back to dequeue_signal where the code reschedules
    timers.   This makes it clear why the code cares about preallocated
    timers.
    
    Cc: stable@vger.kernel.org
    Reported-by: default avatarThomas Gleixner <tglx@linutronix.de>
    History Tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
    Reference: 66dd34ad
    
     ("signal: allow to send any siginfo to itself")
    Reference: 1669ce53e2ff ("Add PTRACE_GETSIGINFO and PTRACE_SETSIGINFO")
    Fixes: db8b50ba75f2 ("[PATCH] POSIX clocks & timers")
    Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
    57db7e4a