From 2e024a535ae85a22ade79de5a51a82f139a15c06 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Feb 27 2023 11:39:25 +0000 Subject: uaccess: Add speculation barrier to copy_from_user() (bsc#1012628). --- diff --git a/patches.kernel.org/6.2.1-001-uaccess-Add-speculation-barrier-to-copy_from_us.patch b/patches.kernel.org/6.2.1-001-uaccess-Add-speculation-barrier-to-copy_from_us.patch new file mode 100644 index 0000000..e46edc8 --- /dev/null +++ b/patches.kernel.org/6.2.1-001-uaccess-Add-speculation-barrier-to-copy_from_us.patch @@ -0,0 +1,116 @@ +From: Dave Hansen +Date: Tue, 21 Feb 2023 12:30:15 -0800 +Subject: [PATCH] uaccess: Add speculation barrier to copy_from_user() +References: bsc#1012628 +Patch-mainline: 6.2.1 +Git-commit: 74e19ef0ff8061ef55957c3abd71614ef0f42f47 + +commit 74e19ef0ff8061ef55957c3abd71614ef0f42f47 upstream. + +The results of "access_ok()" can be mis-speculated. The result is that +you can end speculatively: + + if (access_ok(from, size)) + // Right here + +even for bad from/size combinations. On first glance, it would be ideal +to just add a speculation barrier to "access_ok()" so that its results +can never be mis-speculated. + +But there are lots of system calls just doing access_ok() via +"copy_to_user()" and friends (example: fstat() and friends). Those are +generally not problematic because they do not _consume_ data from +userspace other than the pointer. They are also very quick and common +system calls that should not be needlessly slowed down. + +"copy_from_user()" on the other hand uses a user-controller pointer and +is frequently followed up with code that might affect caches. Take +something like this: + + if (!copy_from_user(&kernelvar, uptr, size)) + do_something_with(kernelvar); + +If userspace passes in an evil 'uptr' that *actually* points to a kernel +addresses, and then do_something_with() has cache (or other) +side-effects, it could allow userspace to infer kernel data values. + +Add a barrier to the common copy_from_user() code to prevent +mis-speculated values which happen after the copy. + +Also add a stub for architectures that do not define barrier_nospec(). +This makes the macro usable in generic code. + +Since the barrier is now usable in generic code, the x86 #ifdef in the +BPF code can also go away. + +Reported-by: Jordy Zomer +Suggested-by: Linus Torvalds +Signed-off-by: Dave Hansen +Reviewed-by: Thomas Gleixner +Acked-by: Daniel Borkmann # BPF bits +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Jiri Slaby +--- + include/linux/nospec.h | 4 ++++ + kernel/bpf/core.c | 2 -- + lib/usercopy.c | 7 +++++++ + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/include/linux/nospec.h b/include/linux/nospec.h +index c1e79f72..9f0af4f1 100644 +--- a/include/linux/nospec.h ++++ b/include/linux/nospec.h +@@ -11,6 +11,10 @@ + + struct task_struct; + ++#ifndef barrier_nospec ++# define barrier_nospec() do { } while (0) ++#endif ++ + /** + * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise + * @index: array element index +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index ba3fff17..430c66d5 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -1910,9 +1910,7 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn) + * reuse preexisting logic from Spectre v1 mitigation that + * happens to produce the required code on x86 for v4 as well. + */ +-#ifdef CONFIG_X86 + barrier_nospec(); +-#endif + CONT; + #define LDST(SIZEOP, SIZE) \ + STX_MEM_##SIZEOP: \ +diff --git a/lib/usercopy.c b/lib/usercopy.c +index 1505a52f..d29fe29c 100644 +--- a/lib/usercopy.c ++++ b/lib/usercopy.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + /* out-of-line parts */ + +@@ -12,6 +13,12 @@ unsigned long _copy_from_user(void *to, const void __user *from, unsigned long n + unsigned long res = n; + might_fault(); + if (!should_fail_usercopy() && likely(access_ok(from, n))) { ++ /* ++ * Ensure that bad access_ok() speculation will not ++ * lead to nasty side effects *after* the copy is ++ * finished: ++ */ ++ barrier_nospec(); + instrument_copy_from_user_before(to, from, n); + res = raw_copy_from_user(to, from, n); + instrument_copy_from_user_after(to, from, n, res); +-- +2.35.3 + diff --git a/series.conf b/series.conf index 1c4964b..eb094a3 100644 --- a/series.conf +++ b/series.conf @@ -27,6 +27,7 @@ # DO NOT MODIFY THEM! # Send separate patches upstream if you find a problem... ######################################################## + patches.kernel.org/6.2.1-001-uaccess-Add-speculation-barrier-to-copy_from_us.patch ######################################################## # Build fixes that apply to the vanilla kernel too.