diff options
| -rw-r--r-- | arch/arm/include/asm/assembler.h | 11 | ||||
| -rw-r--r-- | arch/arm/include/asm/uaccess.h | 26 | ||||
| -rw-r--r-- | arch/arm/lib/copy_from_user.S | 6 |
3 files changed, 38 insertions, 5 deletions
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index f0515f60cff5..39651c1ec157 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h | |||
| @@ -467,6 +467,17 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) | |||
| 467 | #endif | 467 | #endif |
| 468 | .endm | 468 | .endm |
| 469 | 469 | ||
| 470 | .macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req | ||
| 471 | #ifdef CONFIG_CPU_SPECTRE | ||
| 472 | sub \tmp, \limit, #1 | ||
| 473 | subs \tmp, \tmp, \addr @ tmp = limit - 1 - addr | ||
| 474 | addhs \tmp, \tmp, #1 @ if (tmp >= 0) { | ||
| 475 | subhss \tmp, \tmp, \size @ tmp = limit - (addr + size) } | ||
| 476 | movlo \addr, #0 @ if (tmp < 0) addr = NULL | ||
| 477 | csdb | ||
| 478 | #endif | ||
| 479 | .endm | ||
| 480 | |||
| 470 | .macro uaccess_disable, tmp, isb=1 | 481 | .macro uaccess_disable, tmp, isb=1 |
| 471 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN | 482 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN |
| 472 | /* | 483 | /* |
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index cf50b030c62c..a5807b67ca8a 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h | |||
| @@ -100,6 +100,32 @@ static inline void set_fs(mm_segment_t fs) | |||
| 100 | __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) | 100 | __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) |
| 101 | 101 | ||
| 102 | /* | 102 | /* |
| 103 | * Sanitise a uaccess pointer such that it becomes NULL if addr+size | ||
| 104 | * is above the current addr_limit. | ||
| 105 | */ | ||
| 106 | #define uaccess_mask_range_ptr(ptr, size) \ | ||
| 107 | ((__typeof__(ptr))__uaccess_mask_range_ptr(ptr, size)) | ||
| 108 | static inline void __user *__uaccess_mask_range_ptr(const void __user *ptr, | ||
| 109 | size_t size) | ||
| 110 | { | ||
| 111 | void __user *safe_ptr = (void __user *)ptr; | ||
| 112 | unsigned long tmp; | ||
| 113 | |||
| 114 | asm volatile( | ||
| 115 | " sub %1, %3, #1\n" | ||
| 116 | " subs %1, %1, %0\n" | ||
| 117 | " addhs %1, %1, #1\n" | ||
| 118 | " subhss %1, %1, %2\n" | ||
| 119 | " movlo %0, #0\n" | ||
| 120 | : "+r" (safe_ptr), "=&r" (tmp) | ||
| 121 | : "r" (size), "r" (current_thread_info()->addr_limit) | ||
| 122 | : "cc"); | ||
| 123 | |||
| 124 | csdb(); | ||
| 125 | return safe_ptr; | ||
| 126 | } | ||
| 127 | |||
| 128 | /* | ||
| 103 | * Single-value transfer routines. They automatically use the right | 129 | * Single-value transfer routines. They automatically use the right |
| 104 | * size if we just have the right pointer type. Note that the functions | 130 | * size if we just have the right pointer type. Note that the functions |
| 105 | * which read from user space (*get_*) need to take care not to leak | 131 | * which read from user space (*get_*) need to take care not to leak |
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index a826df3d3814..6709a8d33963 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S | |||
| @@ -93,11 +93,7 @@ ENTRY(arm_copy_from_user) | |||
| 93 | #ifdef CONFIG_CPU_SPECTRE | 93 | #ifdef CONFIG_CPU_SPECTRE |
| 94 | get_thread_info r3 | 94 | get_thread_info r3 |
| 95 | ldr r3, [r3, #TI_ADDR_LIMIT] | 95 | ldr r3, [r3, #TI_ADDR_LIMIT] |
| 96 | adds ip, r1, r2 @ ip=addr+size | 96 | uaccess_mask_range_ptr r1, r2, r3, ip |
| 97 | sub r3, r3, #1 @ addr_limit - 1 | ||
| 98 | cmpcc ip, r3 @ if (addr+size > addr_limit - 1) | ||
| 99 | movcs r1, #0 @ addr = NULL | ||
| 100 | csdb | ||
| 101 | #endif | 97 | #endif |
| 102 | 98 | ||
| 103 | #include "copy_template.S" | 99 | #include "copy_template.S" |
