aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/assembler.h11
-rw-r--r--arch/arm/include/asm/uaccess.h26
-rw-r--r--arch/arm/lib/copy_from_user.S6
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))
108static 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"