Skip to content

Commit fc703d8

Browse files
mrutland-armctmarinas
authored andcommitted
arm64: uaccess: split user/kernel routines
This patch separates arm64's user and kernel memory access primitives into distinct routines, adding new __{get,put}_kernel_nofault() helpers to access kernel memory, upon which core code builds larger copy routines. The kernel access routines (using LDR/STR) are not affected by PAN (when legitimately accessing kernel memory), nor are they affected by UAO. Switching to KERNEL_DS may set UAO, but this does not adversely affect the kernel access routines. The user access routines (using LDTR/STTR) are not affected by PAN (when legitimately accessing user memory), but are affected by UAO. As these are only legitimate to use under USER_DS with UAO clear, this should not be problematic. Routines performing atomics to user memory (futex and deprecated instruction emulation) still need to transiently clear PAN, and these are left as-is. These are never used on kernel memory. Subsequent patches will refactor the uaccess helpers to remove redundant code, and will also remove the redundant PAN/UAO manipulation. Signed-off-by: Mark Rutland <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: James Morse <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent f253d82 commit fc703d8

File tree

2 files changed

+47
-65
lines changed

2 files changed

+47
-65
lines changed

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

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -59,62 +59,32 @@ alternative_else_nop_endif
5959
#endif
6060

6161
/*
62-
* Generate the assembly for UAO alternatives with exception table entries.
62+
* Generate the assembly for LDTR/STTR with exception table entries.
6363
* This is complicated as there is no post-increment or pair versions of the
6464
* unprivileged instructions, and USER() only works for single instructions.
6565
*/
66-
#ifdef CONFIG_ARM64_UAO
6766
.macro uao_ldp l, reg1, reg2, addr, post_inc
68-
alternative_if_not ARM64_HAS_UAO
69-
8888: ldp \reg1, \reg2, [\addr], \post_inc;
70-
8889: nop;
71-
nop;
72-
alternative_else
73-
ldtr \reg1, [\addr];
74-
ldtr \reg2, [\addr, #8];
75-
add \addr, \addr, \post_inc;
76-
alternative_endif
67+
8888: ldtr \reg1, [\addr];
68+
8889: ldtr \reg2, [\addr, #8];
69+
add \addr, \addr, \post_inc;
7770

7871
_asm_extable 8888b,\l;
7972
_asm_extable 8889b,\l;
8073
.endm
8174

8275
.macro uao_stp l, reg1, reg2, addr, post_inc
83-
alternative_if_not ARM64_HAS_UAO
84-
8888: stp \reg1, \reg2, [\addr], \post_inc;
85-
8889: nop;
86-
nop;
87-
alternative_else
88-
sttr \reg1, [\addr];
89-
sttr \reg2, [\addr, #8];
90-
add \addr, \addr, \post_inc;
91-
alternative_endif
76+
8888: sttr \reg1, [\addr];
77+
8889: sttr \reg2, [\addr, #8];
78+
add \addr, \addr, \post_inc;
9279

9380
_asm_extable 8888b,\l;
9481
_asm_extable 8889b,\l;
9582
.endm
9683

9784
.macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
98-
alternative_if_not ARM64_HAS_UAO
99-
8888: \inst \reg, [\addr], \post_inc;
100-
nop;
101-
alternative_else
102-
\alt_inst \reg, [\addr];
103-
add \addr, \addr, \post_inc;
104-
alternative_endif
85+
8888: \alt_inst \reg, [\addr];
86+
add \addr, \addr, \post_inc;
10587

10688
_asm_extable 8888b,\l;
10789
.endm
108-
#else
109-
.macro uao_ldp l, reg1, reg2, addr, post_inc
110-
USER(\l, ldp \reg1, \reg2, [\addr], \post_inc)
111-
.endm
112-
.macro uao_stp l, reg1, reg2, addr, post_inc
113-
USER(\l, stp \reg1, \reg2, [\addr], \post_inc)
114-
.endm
115-
.macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
116-
USER(\l, \inst \reg, [\addr], \post_inc)
117-
.endm
118-
#endif
119-
12090
#endif

arch/arm64/include/asm/uaccess.h

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <asm/memory.h>
2525
#include <asm/extable.h>
2626

27+
#define HAVE_GET_KERNEL_NOFAULT
28+
2729
#define get_fs() (current_thread_info()->addr_limit)
2830

2931
static inline void set_fs(mm_segment_t fs)
@@ -253,10 +255,9 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
253255
* The "__xxx_error" versions set the third argument to -EFAULT if an error
254256
* occurs, and leave it unchanged on success.
255257
*/
256-
#define __get_mem_asm(instr, alt_instr, reg, x, addr, err, feature) \
258+
#define __get_mem_asm(load, reg, x, addr, err) \
257259
asm volatile( \
258-
"1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \
259-
alt_instr " " reg "1, [%2]\n", feature) \
260+
"1: " load " " reg "1, [%2]\n" \
260261
"2:\n" \
261262
" .section .fixup, \"ax\"\n" \
262263
" .align 2\n" \
@@ -268,25 +269,21 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
268269
: "+r" (err), "=&r" (x) \
269270
: "r" (addr), "i" (-EFAULT))
270271

271-
#define __raw_get_mem(x, ptr, err) \
272+
#define __raw_get_mem(ldr, x, ptr, err) \
272273
do { \
273274
unsigned long __gu_val; \
274275
switch (sizeof(*(ptr))) { \
275276
case 1: \
276-
__get_mem_asm("ldrb", "ldtrb", "%w", __gu_val, (ptr), \
277-
(err), ARM64_HAS_UAO); \
277+
__get_mem_asm(ldr "b", "%w", __gu_val, (ptr), (err)); \
278278
break; \
279279
case 2: \
280-
__get_mem_asm("ldrh", "ldtrh", "%w", __gu_val, (ptr), \
281-
(err), ARM64_HAS_UAO); \
280+
__get_mem_asm(ldr "h", "%w", __gu_val, (ptr), (err)); \
282281
break; \
283282
case 4: \
284-
__get_mem_asm("ldr", "ldtr", "%w", __gu_val, (ptr), \
285-
(err), ARM64_HAS_UAO); \
283+
__get_mem_asm(ldr, "%w", __gu_val, (ptr), (err)); \
286284
break; \
287285
case 8: \
288-
__get_mem_asm("ldr", "ldtr", "%x", __gu_val, (ptr), \
289-
(err), ARM64_HAS_UAO); \
286+
__get_mem_asm(ldr, "%x", __gu_val, (ptr), (err)); \
290287
break; \
291288
default: \
292289
BUILD_BUG(); \
@@ -298,7 +295,7 @@ do { \
298295
do { \
299296
__chk_user_ptr(ptr); \
300297
uaccess_enable_not_uao(); \
301-
__raw_get_mem(x, ptr, err); \
298+
__raw_get_mem("ldtr", x, ptr, err); \
302299
uaccess_disable_not_uao(); \
303300
} while (0)
304301

@@ -323,10 +320,19 @@ do { \
323320

324321
#define get_user __get_user
325322

326-
#define __put_mem_asm(instr, alt_instr, reg, x, addr, err, feature) \
323+
#define __get_kernel_nofault(dst, src, type, err_label) \
324+
do { \
325+
int __gkn_err = 0; \
326+
\
327+
__raw_get_mem("ldr", *((type *)(dst)), \
328+
(__force type *)(src), __gkn_err); \
329+
if (unlikely(__gkn_err)) \
330+
goto err_label; \
331+
} while (0)
332+
333+
#define __put_mem_asm(store, reg, x, addr, err) \
327334
asm volatile( \
328-
"1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \
329-
alt_instr " " reg "1, [%2]\n", feature) \
335+
"1: " store " " reg "1, [%2]\n" \
330336
"2:\n" \
331337
" .section .fixup,\"ax\"\n" \
332338
" .align 2\n" \
@@ -337,25 +343,21 @@ do { \
337343
: "+r" (err) \
338344
: "r" (x), "r" (addr), "i" (-EFAULT))
339345

340-
#define __raw_put_mem(x, ptr, err) \
346+
#define __raw_put_mem(str, x, ptr, err) \
341347
do { \
342348
__typeof__(*(ptr)) __pu_val = (x); \
343349
switch (sizeof(*(ptr))) { \
344350
case 1: \
345-
__put_mem_asm("strb", "sttrb", "%w", __pu_val, (ptr), \
346-
(err), ARM64_HAS_UAO); \
351+
__put_mem_asm(str "b", "%w", __pu_val, (ptr), (err)); \
347352
break; \
348353
case 2: \
349-
__put_mem_asm("strh", "sttrh", "%w", __pu_val, (ptr), \
350-
(err), ARM64_HAS_UAO); \
354+
__put_mem_asm(str "h", "%w", __pu_val, (ptr), (err)); \
351355
break; \
352356
case 4: \
353-
__put_mem_asm("str", "sttr", "%w", __pu_val, (ptr), \
354-
(err), ARM64_HAS_UAO); \
357+
__put_mem_asm(str, "%w", __pu_val, (ptr), (err)); \
355358
break; \
356359
case 8: \
357-
__put_mem_asm("str", "sttr", "%x", __pu_val, (ptr), \
358-
(err), ARM64_HAS_UAO); \
360+
__put_mem_asm(str, "%x", __pu_val, (ptr), (err)); \
359361
break; \
360362
default: \
361363
BUILD_BUG(); \
@@ -366,7 +368,7 @@ do { \
366368
do { \
367369
__chk_user_ptr(ptr); \
368370
uaccess_enable_not_uao(); \
369-
__raw_put_mem(x, ptr, err); \
371+
__raw_put_mem("sttr", x, ptr, err); \
370372
uaccess_disable_not_uao(); \
371373
} while (0)
372374

@@ -391,6 +393,16 @@ do { \
391393

392394
#define put_user __put_user
393395

396+
#define __put_kernel_nofault(dst, src, type, err_label) \
397+
do { \
398+
int __pkn_err = 0; \
399+
\
400+
__raw_put_mem("str", *((type *)(src)), \
401+
(__force type *)(dst), __pkn_err); \
402+
if (unlikely(__pkn_err)) \
403+
goto err_label; \
404+
} while(0)
405+
394406
extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
395407
#define raw_copy_from_user(to, from, n) \
396408
({ \

0 commit comments

Comments
 (0)