Skip to content

Commit e47b40a

Browse files
committed
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull more arm64 updates from Catalin Marinas: - Silence module allocation failures when CONFIG_ARM*_MODULE_PLTS is enabled. This requires a check for __GFP_NOWARN in alloc_vmap_area() - Improve/sanitise user tagged pointers handling in the kernel - Inline asm fixes/cleanups * tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64: Silence first allocation with CONFIG_ARM64_MODULE_PLTS=y ARM: Silence first allocation with CONFIG_ARM_MODULE_PLTS=y mm: Silence vmap() allocation failures based on caller gfp_flags arm64: uaccess: suppress spurious clang warning arm64: atomic_lse: match asm register sizes arm64: armv8_deprecated: ensure extension of addr arm64: uaccess: ensure extension of access_ok() addr arm64: ensure extension of smp_store_release value arm64: xchg: hazard against entire exchange variable arm64: documentation: document tagged pointer stack constraints arm64: entry: improve data abort handling of tagged pointers arm64: hw_breakpoint: fix watchpoint matching for tagged pointers arm64: traps: fix userspace cache maintenance emulation on a tagged pointer
2 parents 4892c6f + 0c2cf6d commit e47b40a

File tree

13 files changed

+107
-38
lines changed

13 files changed

+107
-38
lines changed

Documentation/arm64/tagged-pointers.txt

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,56 @@ in AArch64 Linux.
1111
The kernel configures the translation tables so that translations made
1212
via TTBR0 (i.e. userspace mappings) have the top byte (bits 63:56) of
1313
the virtual address ignored by the translation hardware. This frees up
14-
this byte for application use, with the following caveats:
14+
this byte for application use.
1515

16-
(1) The kernel requires that all user addresses passed to EL1
17-
are tagged with tag 0x00. This means that any syscall
18-
parameters containing user virtual addresses *must* have
19-
their top byte cleared before trapping to the kernel.
2016

21-
(2) Non-zero tags are not preserved when delivering signals.
22-
This means that signal handlers in applications making use
23-
of tags cannot rely on the tag information for user virtual
24-
addresses being maintained for fields inside siginfo_t.
25-
One exception to this rule is for signals raised in response
26-
to watchpoint debug exceptions, where the tag information
27-
will be preserved.
17+
Passing tagged addresses to the kernel
18+
--------------------------------------
2819

29-
(3) Special care should be taken when using tagged pointers,
30-
since it is likely that C compilers will not hazard two
31-
virtual addresses differing only in the upper byte.
20+
All interpretation of userspace memory addresses by the kernel assumes
21+
an address tag of 0x00.
22+
23+
This includes, but is not limited to, addresses found in:
24+
25+
- pointer arguments to system calls, including pointers in structures
26+
passed to system calls,
27+
28+
- the stack pointer (sp), e.g. when interpreting it to deliver a
29+
signal,
30+
31+
- the frame pointer (x29) and frame records, e.g. when interpreting
32+
them to generate a backtrace or call graph.
33+
34+
Using non-zero address tags in any of these locations may result in an
35+
error code being returned, a (fatal) signal being raised, or other modes
36+
of failure.
37+
38+
For these reasons, passing non-zero address tags to the kernel via
39+
system calls is forbidden, and using a non-zero address tag for sp is
40+
strongly discouraged.
41+
42+
Programs maintaining a frame pointer and frame records that use non-zero
43+
address tags may suffer impaired or inaccurate debug and profiling
44+
visibility.
45+
46+
47+
Preserving tags
48+
---------------
49+
50+
Non-zero tags are not preserved when delivering signals. This means that
51+
signal handlers in applications making use of tags cannot rely on the
52+
tag information for user virtual addresses being maintained for fields
53+
inside siginfo_t. One exception to this rule is for signals raised in
54+
response to watchpoint debug exceptions, where the tag information will
55+
be preserved.
3256

3357
The architecture prevents the use of a tagged PC, so the upper byte will
3458
be set to a sign-extension of bit 55 on exception return.
59+
60+
61+
Other considerations
62+
--------------------
63+
64+
Special care should be taken when using tagged pointers, since it is
65+
likely that C compilers will not hazard two virtual addresses differing
66+
only in the upper byte.

arch/arm/kernel/module.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,15 @@
4040
#ifdef CONFIG_MMU
4141
void *module_alloc(unsigned long size)
4242
{
43-
void *p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
44-
GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
43+
gfp_t gfp_mask = GFP_KERNEL;
44+
void *p;
45+
46+
/* Silence the initial allocation */
47+
if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS))
48+
gfp_mask |= __GFP_NOWARN;
49+
50+
p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
51+
gfp_mask, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
4552
__builtin_return_address(0));
4653
if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p)
4754
return p;

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,13 @@ alternative_if ARM64_ALT_PAN_NOT_UAO
6262
alternative_else_nop_endif
6363
.endm
6464

65+
/*
66+
* Remove the address tag from a virtual address, if present.
67+
*/
68+
.macro clear_address_tag, dst, addr
69+
tst \addr, #(1 << 55)
70+
bic \dst, \addr, #(0xff << 56)
71+
csel \dst, \dst, \addr, eq
72+
.endm
73+
6574
#endif

arch/arm64/include/asm/atomic_lse.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ static inline void atomic64_and(long i, atomic64_t *v)
322322
#define ATOMIC64_FETCH_OP_AND(name, mb, cl...) \
323323
static inline long atomic64_fetch_and##name(long i, atomic64_t *v) \
324324
{ \
325-
register long x0 asm ("w0") = i; \
325+
register long x0 asm ("x0") = i; \
326326
register atomic64_t *x1 asm ("x1") = v; \
327327
\
328328
asm volatile(ARM64_LSE_ATOMIC_INSN( \
@@ -394,7 +394,7 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory")
394394
#define ATOMIC64_FETCH_OP_SUB(name, mb, cl...) \
395395
static inline long atomic64_fetch_sub##name(long i, atomic64_t *v) \
396396
{ \
397-
register long x0 asm ("w0") = i; \
397+
register long x0 asm ("x0") = i; \
398398
register atomic64_t *x1 asm ("x1") = v; \
399399
\
400400
asm volatile(ARM64_LSE_ATOMIC_INSN( \

arch/arm64/include/asm/barrier.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,35 @@
4242
#define __smp_rmb() dmb(ishld)
4343
#define __smp_wmb() dmb(ishst)
4444

45-
#define __smp_store_release(p, v) \
45+
#define __smp_store_release(p, v) \
4646
do { \
47+
union { typeof(*p) __val; char __c[1]; } __u = \
48+
{ .__val = (__force typeof(*p)) (v) }; \
4749
compiletime_assert_atomic_type(*p); \
4850
switch (sizeof(*p)) { \
4951
case 1: \
5052
asm volatile ("stlrb %w1, %0" \
51-
: "=Q" (*p) : "r" (v) : "memory"); \
53+
: "=Q" (*p) \
54+
: "r" (*(__u8 *)__u.__c) \
55+
: "memory"); \
5256
break; \
5357
case 2: \
5458
asm volatile ("stlrh %w1, %0" \
55-
: "=Q" (*p) : "r" (v) : "memory"); \
59+
: "=Q" (*p) \
60+
: "r" (*(__u16 *)__u.__c) \
61+
: "memory"); \
5662
break; \
5763
case 4: \
5864
asm volatile ("stlr %w1, %0" \
59-
: "=Q" (*p) : "r" (v) : "memory"); \
65+
: "=Q" (*p) \
66+
: "r" (*(__u32 *)__u.__c) \
67+
: "memory"); \
6068
break; \
6169
case 8: \
6270
asm volatile ("stlr %1, %0" \
63-
: "=Q" (*p) : "r" (v) : "memory"); \
71+
: "=Q" (*p) \
72+
: "r" (*(__u64 *)__u.__c) \
73+
: "memory"); \
6474
break; \
6575
} \
6676
} while (0)

arch/arm64/include/asm/cmpxchg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static inline unsigned long __xchg_case_##name(unsigned long x, \
4646
" swp" #acq_lse #rel #sz "\t%" #w "3, %" #w "0, %2\n" \
4747
__nops(3) \
4848
" " #nop_lse) \
49-
: "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr) \
49+
: "=&r" (ret), "=&r" (tmp), "+Q" (*(unsigned long *)ptr) \
5050
: "r" (x) \
5151
: cl); \
5252
\

arch/arm64/include/asm/uaccess.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,21 @@ static inline void set_fs(mm_segment_t fs)
6969
*/
7070
#define __range_ok(addr, size) \
7171
({ \
72+
unsigned long __addr = (unsigned long __force)(addr); \
7273
unsigned long flag, roksum; \
7374
__chk_user_ptr(addr); \
7475
asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \
7576
: "=&r" (flag), "=&r" (roksum) \
76-
: "1" (addr), "Ir" (size), \
77+
: "1" (__addr), "Ir" (size), \
7778
"r" (current_thread_info()->addr_limit) \
7879
: "cc"); \
7980
flag; \
8081
})
8182

8283
/*
83-
* When dealing with data aborts or instruction traps we may end up with
84-
* a tagged userland pointer. Clear the tag to get a sane pointer to pass
85-
* on to access_ok(), for instance.
84+
* When dealing with data aborts, watchpoints, or instruction traps we may end
85+
* up with a tagged userland pointer. Clear the tag to get a sane pointer to
86+
* pass on to access_ok(), for instance.
8687
*/
8788
#define untagged_addr(addr) sign_extend64(addr, 55)
8889

@@ -230,7 +231,7 @@ do { \
230231
(err), ARM64_HAS_UAO); \
231232
break; \
232233
case 8: \
233-
__get_user_asm("ldr", "ldtr", "%", __gu_val, (ptr), \
234+
__get_user_asm("ldr", "ldtr", "%x", __gu_val, (ptr), \
234235
(err), ARM64_HAS_UAO); \
235236
break; \
236237
default: \
@@ -297,7 +298,7 @@ do { \
297298
(err), ARM64_HAS_UAO); \
298299
break; \
299300
case 8: \
300-
__put_user_asm("str", "sttr", "%", __pu_val, (ptr), \
301+
__put_user_asm("str", "sttr", "%x", __pu_val, (ptr), \
301302
(err), ARM64_HAS_UAO); \
302303
break; \
303304
default: \

arch/arm64/kernel/armv8_deprecated.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ do { \
306306
_ASM_EXTABLE(0b, 4b) \
307307
_ASM_EXTABLE(1b, 4b) \
308308
: "=&r" (res), "+r" (data), "=&r" (temp), "=&r" (temp2) \
309-
: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT), \
309+
: "r" ((unsigned long)addr), "i" (-EAGAIN), \
310+
"i" (-EFAULT), \
310311
"i" (__SWP_LL_SC_LOOPS) \
311312
: "memory"); \
312313
uaccess_disable(); \

arch/arm64/kernel/entry.S

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,12 +428,13 @@ el1_da:
428428
/*
429429
* Data abort handling
430430
*/
431-
mrs x0, far_el1
431+
mrs x3, far_el1
432432
enable_dbg
433433
// re-enable interrupts if they were enabled in the aborted context
434434
tbnz x23, #7, 1f // PSR_I_BIT
435435
enable_irq
436436
1:
437+
clear_address_tag x0, x3
437438
mov x2, sp // struct pt_regs
438439
bl do_mem_abort
439440

@@ -594,7 +595,7 @@ el0_da:
594595
// enable interrupts before calling the main handler
595596
enable_dbg_and_irq
596597
ct_user_exit
597-
bic x0, x26, #(0xff << 56)
598+
clear_address_tag x0, x26
598599
mov x1, x25
599600
mov x2, sp
600601
bl do_mem_abort

arch/arm64/kernel/hw_breakpoint.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <asm/traps.h>
3737
#include <asm/cputype.h>
3838
#include <asm/system_misc.h>
39+
#include <asm/uaccess.h>
3940

4041
/* Breakpoint currently in use for each BRP. */
4142
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
@@ -721,6 +722,8 @@ static u64 get_distance_from_watchpoint(unsigned long addr, u64 val,
721722
u64 wp_low, wp_high;
722723
u32 lens, lene;
723724

725+
addr = untagged_addr(addr);
726+
724727
lens = __ffs(ctrl->len);
725728
lene = __fls(ctrl->len);
726729

0 commit comments

Comments
 (0)