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 | |
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>
-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 | |||