[PATCH 3/7] x86/uaccess: Give uaccess faults their own handler

From: Andy Lutomirski
Date: Tue May 24 2016 - 18:50:29 EST


This will give us a single piece of code to edit to harden our
uaccess fault handling.

Signed-off-by: Andy Lutomirski <luto@xxxxxxxxxx>
---
arch/x86/include/asm/uaccess.h | 16 ++++++++--------
arch/x86/lib/getuser.S | 12 ++++++------
arch/x86/lib/putuser.S | 10 +++++-----
arch/x86/mm/extable.c | 27 +++++++++++++++++++++++----
4 files changed, 42 insertions(+), 23 deletions(-)

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 5b65b2110167..1bc0d18446d7 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -205,8 +205,8 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
"4: movl %3,%0\n" \
" jmp 3b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 4b) \
- _ASM_EXTABLE(2b, 4b) \
+ _ASM_EXTABLE_HANDLE(1b, 4b, ex_handler_uaccess) \
+ _ASM_EXTABLE_HANDLE(2b, 4b, ex_handler_uaccess) \
: "=r" (err) \
: "A" (x), "r" (addr), "i" (errret), "0" (err))

@@ -374,7 +374,7 @@ do { \
" xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_HANDLE(1b, 3b, ex_handler_uaccess) \
: "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err))

@@ -446,7 +446,7 @@ struct __large_struct { unsigned long buf[100]; };
"3: mov %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_HANDLE(1b, 3b, ex_handler_uaccess) \
: "=r"(err) \
: ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))

@@ -574,7 +574,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \
"\tjmp 2b\n" \
"\t.previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_HANDLE(1b, 3b, ex_handler_uaccess) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "q" (__new), "1" (__old) \
: "memory" \
@@ -590,7 +590,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \
"\tjmp 2b\n" \
"\t.previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_HANDLE(1b, 3b, ex_handler_uaccess) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "r" (__new), "1" (__old) \
: "memory" \
@@ -606,7 +606,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \
"\tjmp 2b\n" \
"\t.previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_HANDLE(1b, 3b, ex_handler_uaccess) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "r" (__new), "1" (__old) \
: "memory" \
@@ -625,7 +625,7 @@ extern void __cmpxchg_wrong_size(void)
"3:\tmov %3, %0\n" \
"\tjmp 2b\n" \
"\t.previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_HANDLE(1b, 3b, ex_handler_uaccess) \
: "+r" (__ret), "=a" (__old), "+m" (*(ptr)) \
: "i" (-EFAULT), "r" (__new), "1" (__old) \
: "memory" \
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 46668cda4ffd..953b7be58300 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -116,12 +116,12 @@ bad_get_user_8:
END(bad_get_user_8)
#endif

- _ASM_EXTABLE(1b,bad_get_user)
- _ASM_EXTABLE(2b,bad_get_user)
- _ASM_EXTABLE(3b,bad_get_user)
+ _ASM_EXTABLE_HANDLE(1b,bad_get_user, ex_handler_uaccess)
+ _ASM_EXTABLE_HANDLE(2b,bad_get_user, ex_handler_uaccess)
+ _ASM_EXTABLE_HANDLE(3b,bad_get_user, ex_handler_uaccess)
#ifdef CONFIG_X86_64
- _ASM_EXTABLE(4b,bad_get_user)
+ _ASM_EXTABLE_HANDLE(4b,bad_get_user, ex_handler_uaccess)
#else
- _ASM_EXTABLE(4b,bad_get_user_8)
- _ASM_EXTABLE(5b,bad_get_user_8)
+ _ASM_EXTABLE_HANDLE(4b,bad_get_user_8, ex_handler_uaccess)
+ _ASM_EXTABLE_HANDLE(5b,bad_get_user_8, ex_handler_uaccess)
#endif
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
index e0817a12d323..16d21d630cc7 100644
--- a/arch/x86/lib/putuser.S
+++ b/arch/x86/lib/putuser.S
@@ -88,10 +88,10 @@ bad_put_user:
EXIT
END(bad_put_user)

- _ASM_EXTABLE(1b,bad_put_user)
- _ASM_EXTABLE(2b,bad_put_user)
- _ASM_EXTABLE(3b,bad_put_user)
- _ASM_EXTABLE(4b,bad_put_user)
+ _ASM_EXTABLE_HANDLE(1b,bad_put_user, ex_handler_uaccess)
+ _ASM_EXTABLE_HANDLE(2b,bad_put_user, ex_handler_uaccess)
+ _ASM_EXTABLE_HANDLE(3b,bad_put_user, ex_handler_uaccess)
+ _ASM_EXTABLE_HANDLE(4b,bad_put_user, ex_handler_uaccess)
#ifdef CONFIG_X86_32
- _ASM_EXTABLE(5b,bad_put_user)
+ _ASM_EXTABLE_HANDLE(5b,bad_put_user, ex_handler_uaccess)
#endif
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index c1a25aca0365..658292fdee5e 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -1,5 +1,5 @@
#include <linux/module.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/traps.h>

typedef bool (*ex_handler_t)(const struct exception_table_entry *,
@@ -26,6 +26,23 @@ bool ex_handler_default(const struct exception_table_entry *fixup,
}
EXPORT_SYMBOL(ex_handler_default);

+static bool uaccess_fault_okay(int trapnr, unsigned long error_code,
+ unsigned long extra)
+{
+ return true;
+}
+
+bool ex_handler_uaccess(const struct exception_table_entry *fixup,
+ struct pt_regs *regs, int trapnr,
+ unsigned long error_code, unsigned long extra)
+{
+ if (!uaccess_fault_okay(trapnr, error_code, extra))
+ return false;
+
+ return ex_handler_default(fixup, regs, trapnr, error_code, extra);
+}
+EXPORT_SYMBOL(ex_handler_uaccess);
+
bool ex_handler_fault(const struct exception_table_entry *fixup,
struct pt_regs *regs, int trapnr,
unsigned long error_code, unsigned long extra)
@@ -41,9 +58,11 @@ bool ex_handler_ext(const struct exception_table_entry *fixup,
unsigned long error_code, unsigned long extra)
{
/* Special hack for uaccess_err */
- current_thread_info()->uaccess_err = 1;
- regs->ip = ex_fixup_addr(fixup);
- return true;
+ bool ret = ex_handler_uaccess(fixup, regs, trapnr, error_code, extra);
+
+ if (ret)
+ current_thread_info()->uaccess_err = 1;
+ return ret;
}
EXPORT_SYMBOL(ex_handler_ext);

--
2.5.5