Patch "posix-timer: Properly check sigevent->sigev_notify" has been added to the 4.9-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
posix-timer: Properly check sigevent->sigev_notify
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
posix-timer-properly-check-sigevent-sigev_notify.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
cef31d9af908243421258f1df35a4a644604efbeMon Sep 17 00:00:00 2001
From: Thomas Gleixner <[email protected]>
Date: Fri, 15 Dec 2017 10:32:03 +0100
Subject: posix-timer: Properly check sigevent->sigev_notify
From: Thomas Gleixner <[email protected]>
commit cef31d9af908243421258f1df35a4a644604efbe upstream.
timer_create() specifies via sigevent->sigev_notify the signal delivery for the new timer. The valid modes are SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD and (SIGEV_SIGNAL | SIGEV_THREAD_ID).
The sanity check in good_sigevent() is only checking the valid combination for the SIGEV_THREAD_ID bit, i.e. SIGEV_SIGNAL, but if SIGEV_THREAD_ID is not set it accepts any random value.
This has no real effects on the posix timer and signal delivery code, but it affects show_timer() which handles the output of /proc/$PID/timers. That function uses a string array to pretty print sigev_notify. The access to that array has no bound checks, so random sigev_notify cause access beyond the array bounds.
Add proper checks for the valid notify modes and remove the SIGEV_THREAD_ID masking from various code pathes as SIGEV_NONE can never be set in combination with SIGEV_THREAD_ID.
--- kernel/time/posix-timers.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-)
kernel/time/posix-timers.c +19 -15
@@ -507,17 +507,22 @@ static struct pid *good_sigevent(sigeven {struct task_struct *rtn = current->group_leader; -if ((event->sigev_notify &SIGEV_THREAD_ID ) && - (!(rtn =find_task_by_vpid (event->sigev_notify_thread_id)) || - !same_thread_group (rtn, current) || - (event->sigev_notify & ~SIGEV_THREAD_ID ) !=SIGEV_SIGNAL )) +switch (event->sigev_notify) { +case SIGEV_SIGNAL |SIGEV_THREAD_ID : + rtn =find_task_by_vpid (event->sigev_notify_thread_id); +if (!rtn || !same_thread_group (rtn, current)) +return NULL ; +/* FALLTHRU */ +case SIGEV_SIGNAL : +case SIGEV_THREAD : +if (event->sigev_signo <=0 || event->sigev_signo >SIGRTMAX ) +return NULL ; +/* FALLTHRU */ +case SIGEV_NONE : +return task_pid (rtn); +default :return NULL ; - -if (((event->sigev_notify & ~SIGEV_THREAD_ID ) !=SIGEV_NONE ) && - ((event->sigev_signo <=0 ) || (event->sigev_signo >SIGRTMAX ))) -return NULL ; - -return task_pid (rtn); + } } void posix_timers_register_clock(const clockid_t clock_id,
@@ -745,8 +750,7 @@ common_timer_get(struct k_itimer *timr,/* interval timer ? */ if (iv.tv64) cur_setting->it_interval =ktime_to_timespec (iv); -else if (!hrtimer_active (timer) && - (timr->it_sigev_notify & ~SIGEV_THREAD_ID ) !=SIGEV_NONE ) +else if (!hrtimer_active (timer) && timr->it_sigev_notify !=SIGEV_NONE )return ; now = timer->base->get_time ();
@@ -757,7 +761,7 @@ common_timer_get(struct k_itimer *timr,* expiry is > now. */ if (iv.tv64 && (timr->it_requeue_pending &REQUEUE_PENDING || - (timr->it_sigev_notify & ~SIGEV_THREAD_ID ) ==SIGEV_NONE )) + timr->it_sigev_notify ==SIGEV_NONE )) timr->it_overrun += (unsigned int )hrtimer_forward (timer, now, iv); remaining =__hrtimer_expires_remaining_adjusted (timer, now);
@@ -767,7 +771,7 @@ common_timer_get(struct k_itimer *timr,* A single shot SIGEV_NONE timer must return 0, when * it is expired ! */ -if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID ) !=SIGEV_NONE ) +if (timr->it_sigev_notify !=SIGEV_NONE ) cur_setting->it_value.tv_nsec =1 ; }else cur_setting->it_value =ktime_to_timespec (remaining);
@@ -865,7 +869,7 @@ common_timer_set(struct k_itimer *timr, timr->it.real.interval =timespec_to_ktime (new_setting->it_interval);/* SIGEV_NONE timers are not queued ! See common_timer_get */ -if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID ) ==SIGEV_NONE )) { +if (timr->it_sigev_notify ==SIGEV_NONE ) {/* Setup correct expiry time for relative timers */ if (mode ==HRTIMER_MODE_REL ) {hrtimer_add_expires (timer, timer->base->get_time ());
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/sched-rt-use-container_of-to-get-root-domain-in-rto_push_irq_work_func.patch queue-4.9/posix-timer-properly-check-sigevent-sigev_notify.patch queue-4.9/sched-rt-up-the-root-domain-ref-count-when-passing-it-around-via-ipis.patch