aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Murphy <robin.murphy@arm.com>2018-02-19 08:38:00 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2018-02-19 08:59:58 -0500
commit9085b34d0e8361595a7d19034c550d5d15044556 (patch)
tree1c93d515a8c65e8ce5f8a2afd46c8adc5832a226
parent04c4927359b1f09310bfee92e7187c9022be3e00 (diff)
arm64: uaccess: Formalise types for access_ok()
In converting __range_ok() into a static inline, I inadvertently made it more type-safe, but without considering the ordering of the relevant conversions. This leads to quite a lot of Sparse noise about the fact that we use __chk_user_ptr() after addr has already been converted from a user pointer to an unsigned long. Rather than just adding another cast for the sake of shutting Sparse up, it seems reasonable to rework the types to make logical sense (although the resulting codegen for __range_ok() remains identical). The only callers this affects directly are our compat traps where the inferred "user-pointer-ness" of a register value now warrants explicit casting. Signed-off-by: Robin Murphy <robin.murphy@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm64/include/asm/uaccess.h12
-rw-r--r--arch/arm64/kernel/armv8_deprecated.c4
-rw-r--r--arch/arm64/kernel/sys_compat.c2
3 files changed, 10 insertions, 8 deletions
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 543e11f0f657..e66b0fca99c2 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -72,15 +72,15 @@ static inline void set_fs(mm_segment_t fs)
72 * This is equivalent to the following test: 72 * This is equivalent to the following test:
73 * (u65)addr + (u65)size <= (u65)current->addr_limit + 1 73 * (u65)addr + (u65)size <= (u65)current->addr_limit + 1
74 */ 74 */
75static inline unsigned long __range_ok(unsigned long addr, unsigned long size) 75static inline unsigned long __range_ok(const void __user *addr, unsigned long size)
76{ 76{
77 unsigned long limit = current_thread_info()->addr_limit; 77 unsigned long ret, limit = current_thread_info()->addr_limit;
78 78
79 __chk_user_ptr(addr); 79 __chk_user_ptr(addr);
80 asm volatile( 80 asm volatile(
81 // A + B <= C + 1 for all A,B,C, in four easy steps: 81 // A + B <= C + 1 for all A,B,C, in four easy steps:
82 // 1: X = A + B; X' = X % 2^64 82 // 1: X = A + B; X' = X % 2^64
83 " adds %0, %0, %2\n" 83 " adds %0, %3, %2\n"
84 // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4 84 // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4
85 " csel %1, xzr, %1, hi\n" 85 " csel %1, xzr, %1, hi\n"
86 // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X' 86 // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X'
@@ -92,9 +92,9 @@ static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
92 // testing X' - C == 0, subject to the previous adjustments. 92 // testing X' - C == 0, subject to the previous adjustments.
93 " sbcs xzr, %0, %1\n" 93 " sbcs xzr, %0, %1\n"
94 " cset %0, ls\n" 94 " cset %0, ls\n"
95 : "+r" (addr), "+r" (limit) : "Ir" (size) : "cc"); 95 : "=&r" (ret), "+r" (limit) : "Ir" (size), "0" (addr) : "cc");
96 96
97 return addr; 97 return ret;
98} 98}
99 99
100/* 100/*
@@ -104,7 +104,7 @@ static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
104 */ 104 */
105#define untagged_addr(addr) sign_extend64(addr, 55) 105#define untagged_addr(addr) sign_extend64(addr, 55)
106 106
107#define access_ok(type, addr, size) __range_ok((unsigned long)(addr), size) 107#define access_ok(type, addr, size) __range_ok(addr, size)
108#define user_addr_max get_fs 108#define user_addr_max get_fs
109 109
110#define _ASM_EXTABLE(from, to) \ 110#define _ASM_EXTABLE(from, to) \
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index c33b5e4010ab..68450e954d47 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -370,6 +370,7 @@ static unsigned int __kprobes aarch32_check_condition(u32 opcode, u32 psr)
370static int swp_handler(struct pt_regs *regs, u32 instr) 370static int swp_handler(struct pt_regs *regs, u32 instr)
371{ 371{
372 u32 destreg, data, type, address = 0; 372 u32 destreg, data, type, address = 0;
373 const void __user *user_ptr;
373 int rn, rt2, res = 0; 374 int rn, rt2, res = 0;
374 375
375 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc); 376 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
@@ -401,7 +402,8 @@ static int swp_handler(struct pt_regs *regs, u32 instr)
401 aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data); 402 aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data);
402 403
403 /* Check access in reasonable access range for both SWP and SWPB */ 404 /* Check access in reasonable access range for both SWP and SWPB */
404 if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) { 405 user_ptr = (const void __user *)(unsigned long)(address & ~3);
406 if (!access_ok(VERIFY_WRITE, user_ptr, 4)) {
405 pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", 407 pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n",
406 address); 408 address);
407 goto fault; 409 goto fault;
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index 8b8bbd3eaa52..a382b2a1b84e 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -57,7 +57,7 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags)
57 if (end < start || flags) 57 if (end < start || flags)
58 return -EINVAL; 58 return -EINVAL;
59 59
60 if (!access_ok(VERIFY_READ, start, end - start)) 60 if (!access_ok(VERIFY_READ, (const void __user *)start, end - start))
61 return -EFAULT; 61 return -EFAULT;
62 62
63 return __do_compat_cache_op(start, end); 63 return __do_compat_cache_op(start, end);