Skip to content

Commit 2e77a62

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: extable: add a dedicated uaccess handler
For inline assembly, we place exception fixups out-of-line in the `.fixup` section such that these are out of the way of the fast path. This has a few drawbacks: * Since the fixup code is anonymous, backtraces will symbolize fixups as offsets from the nearest prior symbol, currently `__entry_tramp_text_end`. This is confusing, and painful to debug without access to the relevant vmlinux. * Since the exception handler adjusts the PC to execute the fixup, and the fixup uses a direct branch back into the function it fixes, backtraces of fixups miss the original function. This is confusing, and violates requirements for RELIABLE_STACKTRACE (and therefore LIVEPATCH). * Inline assembly and associated fixups are generated from templates, and we have many copies of logically identical fixups which only differ in which specific registers are written to and which address is branched to at the end of the fixup. This is potentially wasteful of I-cache resources, and makes it hard to add additional logic to fixups without significant bloat. This patch address all three concerns for inline uaccess fixups by adding a dedicated exception handler which updates registers in exception context and subsequent returns back into the function which faulted, removing the need for fixups specialized to each faulting instruction. Other than backtracing, there should be no functional change as a result of this patch. Signed-off-by: Mark Rutland <[email protected]> Reviewed-by: Ard Biesheuvel <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: James Morse <[email protected]> Cc: Robin Murphy <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent d6e2cc5 commit 2e77a62

File tree

6 files changed

+58
-48
lines changed

6 files changed

+58
-48
lines changed

arch/arm64/include/asm/asm-extable.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define EX_TYPE_NONE 0
66
#define EX_TYPE_FIXUP 1
77
#define EX_TYPE_BPF 2
8+
#define EX_TYPE_UACCESS_ERR_ZERO 3
89

910
#ifdef __ASSEMBLY__
1011

@@ -37,8 +38,11 @@
3738

3839
#else /* __ASSEMBLY__ */
3940

41+
#include <linux/bits.h>
4042
#include <linux/stringify.h>
4143

44+
#include <asm/gpr-num.h>
45+
4246
#define __ASM_EXTABLE_RAW(insn, fixup, type, data) \
4347
".pushsection __ex_table, \"a\"\n" \
4448
".align 2\n" \
@@ -51,6 +55,26 @@
5155
#define _ASM_EXTABLE(insn, fixup) \
5256
__ASM_EXTABLE_RAW(#insn, #fixup, __stringify(EX_TYPE_FIXUP), "0")
5357

58+
#define EX_DATA_REG_ERR_SHIFT 0
59+
#define EX_DATA_REG_ERR GENMASK(4, 0)
60+
#define EX_DATA_REG_ZERO_SHIFT 5
61+
#define EX_DATA_REG_ZERO GENMASK(9, 5)
62+
63+
#define EX_DATA_REG(reg, gpr) \
64+
"((.L__gpr_num_" #gpr ") << " __stringify(EX_DATA_REG_##reg##_SHIFT) ")"
65+
66+
#define _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero) \
67+
__DEFINE_ASM_GPR_NUMS \
68+
__ASM_EXTABLE_RAW(#insn, #fixup, \
69+
__stringify(EX_TYPE_UACCESS_ERR_ZERO), \
70+
"(" \
71+
EX_DATA_REG(ERR, err) " | " \
72+
EX_DATA_REG(ZERO, zero) \
73+
")")
74+
75+
#define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err) \
76+
_ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, wzr)
77+
5478
#endif /* __ASSEMBLY__ */
5579

5680
#endif /* __ASM_ASM_EXTABLE_H */

arch/arm64/include/asm/futex.h

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,14 @@ do { \
2525
" cbz %w0, 3f\n" \
2626
" sub %w4, %w4, %w0\n" \
2727
" cbnz %w4, 1b\n" \
28-
" mov %w0, %w7\n" \
28+
" mov %w0, %w6\n" \
2929
"3:\n" \
3030
" dmb ish\n" \
31-
" .pushsection .fixup,\"ax\"\n" \
32-
" .align 2\n" \
33-
"4: mov %w0, %w6\n" \
34-
" b 3b\n" \
35-
" .popsection\n" \
36-
_ASM_EXTABLE(1b, 4b) \
37-
_ASM_EXTABLE(2b, 4b) \
31+
_ASM_EXTABLE_UACCESS_ERR(1b, 3b, %w0) \
32+
_ASM_EXTABLE_UACCESS_ERR(2b, 3b, %w0) \
3833
: "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp), \
3934
"+r" (loops) \
40-
: "r" (oparg), "Ir" (-EFAULT), "Ir" (-EAGAIN) \
35+
: "r" (oparg), "Ir" (-EAGAIN) \
4136
: "memory"); \
4237
uaccess_disable_privileged(); \
4338
} while (0)
@@ -105,18 +100,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
105100
" cbz %w3, 3f\n"
106101
" sub %w4, %w4, %w3\n"
107102
" cbnz %w4, 1b\n"
108-
" mov %w0, %w8\n"
103+
" mov %w0, %w7\n"
109104
"3:\n"
110105
" dmb ish\n"
111106
"4:\n"
112-
" .pushsection .fixup,\"ax\"\n"
113-
"5: mov %w0, %w7\n"
114-
" b 4b\n"
115-
" .popsection\n"
116-
_ASM_EXTABLE(1b, 5b)
117-
_ASM_EXTABLE(2b, 5b)
107+
_ASM_EXTABLE_UACCESS_ERR(1b, 4b, %w0)
108+
_ASM_EXTABLE_UACCESS_ERR(2b, 4b, %w0)
118109
: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp), "+r" (loops)
119-
: "r" (oldval), "r" (newval), "Ir" (-EFAULT), "Ir" (-EAGAIN)
110+
: "r" (oldval), "r" (newval), "Ir" (-EAGAIN)
120111
: "memory");
121112
uaccess_disable_privileged();
122113

arch/arm64/include/asm/uaccess.h

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -255,15 +255,9 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
255255
asm volatile( \
256256
"1: " load " " reg "1, [%2]\n" \
257257
"2:\n" \
258-
" .section .fixup, \"ax\"\n" \
259-
" .align 2\n" \
260-
"3: mov %w0, %3\n" \
261-
" mov %1, #0\n" \
262-
" b 2b\n" \
263-
" .previous\n" \
264-
_ASM_EXTABLE(1b, 3b) \
258+
_ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %w0, %w1) \
265259
: "+r" (err), "=&r" (x) \
266-
: "r" (addr), "i" (-EFAULT))
260+
: "r" (addr))
267261

268262
#define __raw_get_mem(ldr, x, ptr, err) \
269263
do { \
@@ -332,14 +326,9 @@ do { \
332326
asm volatile( \
333327
"1: " store " " reg "1, [%2]\n" \
334328
"2:\n" \
335-
" .section .fixup,\"ax\"\n" \
336-
" .align 2\n" \
337-
"3: mov %w0, %3\n" \
338-
" b 2b\n" \
339-
" .previous\n" \
340-
_ASM_EXTABLE(1b, 3b) \
329+
_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0) \
341330
: "+r" (err) \
342-
: "r" (x), "r" (addr), "i" (-EFAULT))
331+
: "r" (x), "r" (addr))
343332

344333
#define __raw_put_mem(str, x, ptr, err) \
345334
do { \

arch/arm64/kernel/armv8_deprecated.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ static void __init register_insn_emulation_sysctl(void)
279279
do { \
280280
uaccess_enable_privileged(); \
281281
__asm__ __volatile__( \
282-
" mov %w3, %w7\n" \
282+
" mov %w3, %w6\n" \
283283
"0: ldxr"B" %w2, [%4]\n" \
284284
"1: stxr"B" %w0, %w1, [%4]\n" \
285285
" cbz %w0, 2f\n" \
@@ -290,16 +290,10 @@ do { \
290290
"2:\n" \
291291
" mov %w1, %w2\n" \
292292
"3:\n" \
293-
" .pushsection .fixup,\"ax\"\n" \
294-
" .align 2\n" \
295-
"4: mov %w0, %w6\n" \
296-
" b 3b\n" \
297-
" .popsection" \
298-
_ASM_EXTABLE(0b, 4b) \
299-
_ASM_EXTABLE(1b, 4b) \
293+
_ASM_EXTABLE_UACCESS_ERR(0b, 3b, %w0) \
294+
_ASM_EXTABLE_UACCESS_ERR(1b, 3b, %w0) \
300295
: "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \
301296
: "r" ((unsigned long)addr), "i" (-EAGAIN), \
302-
"i" (-EFAULT), \
303297
"i" (__SWP_LL_SC_LOOPS) \
304298
: "memory"); \
305299
uaccess_disable_privileged(); \

arch/arm64/kernel/traps.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -527,14 +527,9 @@ NOKPROBE_SYMBOL(do_ptrauth_fault);
527527
"1: " insn ", %1\n" \
528528
" mov %w0, #0\n" \
529529
"2:\n" \
530-
" .pushsection .fixup,\"ax\"\n" \
531-
" .align 2\n" \
532-
"3: mov %w0, %w2\n" \
533-
" b 2b\n" \
534-
" .popsection\n" \
535-
_ASM_EXTABLE(1b, 3b) \
530+
_ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w0) \
536531
: "=r" (res) \
537-
: "r" (address), "i" (-EFAULT)); \
532+
: "r" (address)); \
538533
uaccess_ttbr0_disable(); \
539534
}
540535

arch/arm64/mm/extable.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
* Based on arch/arm/mm/extable.c
44
*/
55

6+
#include <linux/bitfield.h>
67
#include <linux/extable.h>
78
#include <linux/uaccess.h>
89

910
#include <asm/asm-extable.h>
11+
#include <asm/ptrace.h>
1012

1113
typedef bool (*ex_handler_t)(const struct exception_table_entry *,
1214
struct pt_regs *);
@@ -24,6 +26,19 @@ static bool ex_handler_fixup(const struct exception_table_entry *ex,
2426
return true;
2527
}
2628

29+
static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex,
30+
struct pt_regs *regs)
31+
{
32+
int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
33+
int reg_zero = FIELD_GET(EX_DATA_REG_ZERO, ex->data);
34+
35+
pt_regs_write_reg(regs, reg_err, -EFAULT);
36+
pt_regs_write_reg(regs, reg_zero, 0);
37+
38+
regs->pc = get_ex_fixup(ex);
39+
return true;
40+
}
41+
2742
bool fixup_exception(struct pt_regs *regs)
2843
{
2944
const struct exception_table_entry *ex;
@@ -37,6 +52,8 @@ bool fixup_exception(struct pt_regs *regs)
3752
return ex_handler_fixup(ex, regs);
3853
case EX_TYPE_BPF:
3954
return ex_handler_bpf(ex, regs);
55+
case EX_TYPE_UACCESS_ERR_ZERO:
56+
return ex_handler_uaccess_err_zero(ex, regs);
4057
}
4158

4259
BUG();

0 commit comments

Comments
 (0)