diff options
| author | Andreas Wellving <andreas.wellving@enea.com> | 2018-10-12 09:28:42 +0200 |
|---|---|---|
| committer | Andreas Wellving <andreas.wellving@enea.com> | 2018-10-12 09:28:42 +0200 |
| commit | 307a37fe48bfc9ce3297526b6d6e7d1bf1758448 (patch) | |
| tree | 5cc3e682cb01bd18ab146699a43577c4ecdadf35 /patches/cve | |
| parent | bbbaee9150a62c2965710ff2245b65da32f35eb5 (diff) | |
| download | enea-kernel-cache-307a37fe48bfc9ce3297526b6d6e7d1bf1758448.tar.gz | |
posix-timer: CVE-2017-18344
posix-timer: Properly check sigevent->sigev_notify
References:
https://github.com/torvalds/linux/commit/cef31d9af908243421258f1df35a4a644604efbe
Change-Id: I1cea661130c10f10cc2b3ffc480fff9d8ed3ee0e
Signed-off-by: Andreas Wellving <andreas.wellving@enea.com>
Diffstat (limited to 'patches/cve')
| -rw-r--r-- | patches/cve/4.9.x.scc | 2 | ||||
| -rw-r--r-- | patches/cve/CVE-2017-18344-posix-timer-Properly-check-sigevent-sigev_notify.patch | 113 |
2 files changed, 115 insertions, 0 deletions
diff --git a/patches/cve/4.9.x.scc b/patches/cve/4.9.x.scc new file mode 100644 index 0000000..4fa6185 --- /dev/null +++ b/patches/cve/4.9.x.scc | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | #CVEs fixed in 4.9.82: | ||
| 2 | patch CVE-2017-18344-posix-timer-Properly-check-sigevent-sigev_notify.patch | ||
diff --git a/patches/cve/CVE-2017-18344-posix-timer-Properly-check-sigevent-sigev_notify.patch b/patches/cve/CVE-2017-18344-posix-timer-Properly-check-sigevent-sigev_notify.patch new file mode 100644 index 0000000..ebab261 --- /dev/null +++ b/patches/cve/CVE-2017-18344-posix-timer-Properly-check-sigevent-sigev_notify.patch | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | Date: Thu, 11 Oct 2018 15:28:37 +0200 | ||
| 2 | Subject: [PATCH] posix-timer: Properly check sigevent->sigev_notify | ||
| 3 | |||
| 4 | commit cef31d9af908243421258f1df35a4a644604efbe upstream. | ||
| 5 | |||
| 6 | timer_create() specifies via sigevent->sigev_notify the signal delivery for | ||
| 7 | the new timer. The valid modes are SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD | ||
| 8 | and (SIGEV_SIGNAL | SIGEV_THREAD_ID). | ||
| 9 | |||
| 10 | The sanity check in good_sigevent() is only checking the valid combination | ||
| 11 | for the SIGEV_THREAD_ID bit, i.e. SIGEV_SIGNAL, but if SIGEV_THREAD_ID is | ||
| 12 | not set it accepts any random value. | ||
| 13 | |||
| 14 | This has no real effects on the posix timer and signal delivery code, but | ||
| 15 | it affects show_timer() which handles the output of /proc/$PID/timers. That | ||
| 16 | function uses a string array to pretty print sigev_notify. The access to | ||
| 17 | that array has no bound checks, so random sigev_notify cause access beyond | ||
| 18 | the array bounds. | ||
| 19 | |||
| 20 | Add proper checks for the valid notify modes and remove the SIGEV_THREAD_ID | ||
| 21 | masking from various code pathes as SIGEV_NONE can never be set in | ||
| 22 | combination with SIGEV_THREAD_ID. | ||
| 23 | |||
| 24 | CVE: CVE-2017-18344 | ||
| 25 | Upstream-Status: Backport | ||
| 26 | |||
| 27 | Reported-by: Eric Biggers <ebiggers3@gmail.com> | ||
| 28 | Reported-by: Dmitry Vyukov <dvyukov@google.com> | ||
| 29 | Reported-by: Alexey Dobriyan <adobriyan@gmail.com> | ||
| 30 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | ||
| 31 | Cc: John Stultz <john.stultz@linaro.org> | ||
| 32 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
| 33 | Signed-off-by: Andreas Wellving <andreas.wellving@enea.com> | ||
| 34 | --- | ||
| 35 | kernel/time/posix-timers.c | 33 +++++++++++++++++++-------------- | ||
| 36 | 1 file changed, 19 insertions(+), 14 deletions(-) | ||
| 37 | |||
| 38 | diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c | ||
| 39 | index f2826c3..72c40d3 100644 | ||
| 40 | --- a/kernel/time/posix-timers.c | ||
| 41 | +++ b/kernel/time/posix-timers.c | ||
| 42 | @@ -507,17 +507,22 @@ static struct pid *good_sigevent(sigevent_t * event) | ||
| 43 | { | ||
| 44 | struct task_struct *rtn = current->group_leader; | ||
| 45 | |||
| 46 | - if ((event->sigev_notify & SIGEV_THREAD_ID ) && | ||
| 47 | - (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) || | ||
| 48 | - !same_thread_group(rtn, current) || | ||
| 49 | - (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL)) | ||
| 50 | + switch (event->sigev_notify) { | ||
| 51 | + case SIGEV_SIGNAL | SIGEV_THREAD_ID: | ||
| 52 | + rtn = find_task_by_vpid(event->sigev_notify_thread_id); | ||
| 53 | + if (!rtn || !same_thread_group(rtn, current)) | ||
| 54 | + return NULL; | ||
| 55 | + /* FALLTHRU */ | ||
| 56 | + case SIGEV_SIGNAL: | ||
| 57 | + case SIGEV_THREAD: | ||
| 58 | + if (event->sigev_signo <= 0 || event->sigev_signo > SIGRTMAX) | ||
| 59 | + return NULL; | ||
| 60 | + /* FALLTHRU */ | ||
| 61 | + case SIGEV_NONE: | ||
| 62 | + return task_pid(rtn); | ||
| 63 | + default: | ||
| 64 | return NULL; | ||
| 65 | - | ||
| 66 | - if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) && | ||
| 67 | - ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX))) | ||
| 68 | - return NULL; | ||
| 69 | - | ||
| 70 | - return task_pid(rtn); | ||
| 71 | + } | ||
| 72 | } | ||
| 73 | |||
| 74 | void posix_timers_register_clock(const clockid_t clock_id, | ||
| 75 | @@ -746,7 +751,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) | ||
| 76 | if (iv.tv64) | ||
| 77 | cur_setting->it_interval = ktime_to_timespec(iv); | ||
| 78 | else if (!hrtimer_active(timer) && | ||
| 79 | - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) | ||
| 80 | + timr->it_sigev_notify != SIGEV_NONE) | ||
| 81 | return; | ||
| 82 | |||
| 83 | now = timer->base->get_time(); | ||
| 84 | @@ -757,7 +762,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) | ||
| 85 | * expiry is > now. | ||
| 86 | */ | ||
| 87 | if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING || | ||
| 88 | - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) | ||
| 89 | + timr->it_sigev_notify == SIGEV_NONE)) | ||
| 90 | timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv); | ||
| 91 | |||
| 92 | remaining = __hrtimer_expires_remaining_adjusted(timer, now); | ||
| 93 | @@ -767,7 +772,7 @@ common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) | ||
| 94 | * A single shot SIGEV_NONE timer must return 0, when | ||
| 95 | * it is expired ! | ||
| 96 | */ | ||
| 97 | - if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) | ||
| 98 | + if (timr->it_sigev_notify != SIGEV_NONE) | ||
| 99 | cur_setting->it_value.tv_nsec = 1; | ||
| 100 | } else | ||
| 101 | cur_setting->it_value = ktime_to_timespec(remaining); | ||
| 102 | @@ -865,7 +870,7 @@ common_timer_set(struct k_itimer *timr, int flags, | ||
| 103 | timr->it.real.interval = timespec_to_ktime(new_setting->it_interval); | ||
| 104 | |||
| 105 | /* SIGEV_NONE timers are not queued ! See common_timer_get */ | ||
| 106 | - if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { | ||
| 107 | + if (timr->it_sigev_notify == SIGEV_NONE) { | ||
| 108 | /* Setup correct expiry time for relative timers */ | ||
| 109 | if (mode == HRTIMER_MODE_REL) { | ||
| 110 | hrtimer_add_expires(timer, timer->base->get_time()); | ||
| 111 | -- | ||
| 112 | |||
| 113 | |||
