| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Thu, 15 Feb 2018 17:21:55 +0100 |
| Subject: posix-timers: Protect posix clock array access against speculation |
| |
| commit 19b558db12f9f4e45a22012bae7b4783e62224da upstream. |
| |
| The clockid argument of clockid_to_kclock() comes straight from user space |
| via various syscalls and is used as index into the posix_clocks array. |
| |
| Protect it against spectre v1 array out of bounds speculation. Remove the |
| redundant check for !posix_clock[id] as this is another source for |
| speculation and does not provide any advantage over the return |
| posix_clock[id] path which returns NULL in that case anyway. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Acked-by: Dan Williams <dan.j.williams@intel.com> |
| Cc: Rasmus Villemoes <rasmus.villemoes@prevas.dk> |
| Cc: Greg KH <gregkh@linuxfoundation.org> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: David Woodhouse <dwmw@amazon.co.uk> |
| Link: https://lkml.kernel.org/r/alpine.DEB.2.21.1802151718320.1296@nanos.tec.linutronix.de |
| [bwh: Backported to 3.16: |
| - Move the test of the clock_getres field below the lookup using |
| array_index_nospec() |
| - Adjust filename, context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| --- a/kernel/posix-timers.c |
| +++ b/kernel/posix-timers.c |
| @@ -48,6 +48,7 @@ |
| #include <linux/workqueue.h> |
| #include <linux/export.h> |
| #include <linux/hashtable.h> |
| +#include <linux/nospec.h> |
| |
| /* |
| * Management arrays for POSIX timers. Timers are now kept in static hash table |
| @@ -578,13 +579,21 @@ static void release_posix_timer(struct k |
| |
| static struct k_clock *clockid_to_kclock(const clockid_t id) |
| { |
| - if (id < 0) |
| + clockid_t idx = id; |
| + struct k_clock *kc; |
| + |
| + if (id < 0) { |
| return (id & CLOCKFD_MASK) == CLOCKFD ? |
| &clock_posix_dynamic : &clock_posix_cpu; |
| + } |
| + |
| + if (id >= ARRAY_SIZE(posix_clocks)) |
| + return NULL; |
| |
| - if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres) |
| + kc = &posix_clocks[array_index_nospec(idx, ARRAY_SIZE(posix_clocks))]; |
| + if (!kc->clock_getres) |
| return NULL; |
| - return &posix_clocks[id]; |
| + return kc; |
| } |
| |
| static int common_timer_create(struct k_itimer *new_timer) |