Commit 87261d19 authored by Andre Przywara's avatar Andre Przywara Committed by Will Deacon

arm64: Cortex-A53 errata workaround: check for kernel addresses

Commit 7dd01aef ("arm64: trap userspace "dc cvau" cache operation on
errata-affected core") adds code to execute cache maintenance instructions
in the kernel on behalf of userland on CPUs with certain ARM CPU errata.
It turns out that the address hasn't been checked to be a valid user
space address, allowing userland to clean cache lines in kernel space.
Fix this by introducing an address check before executing the
instructions on behalf of userland.

Since the address doesn't come via a syscall parameter, we can't just
reject tagged pointers and instead have to remove the tag when checking
against the user address limit.

Cc: <stable@vger.kernel.org>
Fixes: 7dd01aef ("arm64: trap userspace "dc cvau" cache operation on errata-affected core")
Reported-by: default avatarKristina Martsenko <kristina.martsenko@arm.com>
Signed-off-by: default avatarAndre Przywara <andre.przywara@arm.com>
[will: rework commit message + replace access_ok with max_user_addr()]
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 1e6e57d9
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
/* /*
* User space memory access functions * User space memory access functions
*/ */
#include <linux/bitops.h>
#include <linux/kasan-checks.h> #include <linux/kasan-checks.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/thread_info.h> #include <linux/thread_info.h>
...@@ -102,6 +103,13 @@ static inline void set_fs(mm_segment_t fs) ...@@ -102,6 +103,13 @@ static inline void set_fs(mm_segment_t fs)
flag; \ flag; \
}) })
/*
* When dealing with data aborts or instruction traps we may end up with
* a tagged userland pointer. Clear the tag to get a sane pointer to pass
* on to access_ok(), for instance.
*/
#define untagged_addr(addr) sign_extend64(addr, 55)
#define access_ok(type, addr, size) __range_ok(addr, size) #define access_ok(type, addr, size) __range_ok(addr, size)
#define user_addr_max get_fs #define user_addr_max get_fs
......
...@@ -434,18 +434,21 @@ void cpu_enable_cache_maint_trap(void *__unused) ...@@ -434,18 +434,21 @@ void cpu_enable_cache_maint_trap(void *__unused)
} }
#define __user_cache_maint(insn, address, res) \ #define __user_cache_maint(insn, address, res) \
asm volatile ( \ if (untagged_addr(address) >= user_addr_max()) \
"1: " insn ", %1\n" \ res = -EFAULT; \
" mov %w0, #0\n" \ else \
"2:\n" \ asm volatile ( \
" .pushsection .fixup,\"ax\"\n" \ "1: " insn ", %1\n" \
" .align 2\n" \ " mov %w0, #0\n" \
"3: mov %w0, %w2\n" \ "2:\n" \
" b 2b\n" \ " .pushsection .fixup,\"ax\"\n" \
" .popsection\n" \ " .align 2\n" \
_ASM_EXTABLE(1b, 3b) \ "3: mov %w0, %w2\n" \
: "=r" (res) \ " b 2b\n" \
: "r" (address), "i" (-EFAULT) ) " .popsection\n" \
_ASM_EXTABLE(1b, 3b) \
: "=r" (res) \
: "r" (address), "i" (-EFAULT) )
static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs) static void user_cache_maint_handler(unsigned int esr, struct pt_regs *regs)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment