.. | .. |
---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
---|
1 | 2 | /* |
---|
2 | 3 | * arch/arm/include/asm/uaccess.h |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify |
---|
5 | | - * it under the terms of the GNU General Public License version 2 as |
---|
6 | | - * published by the Free Software Foundation. |
---|
7 | 4 | */ |
---|
8 | 5 | #ifndef _ASMARM_UACCESS_H |
---|
9 | 6 | #define _ASMARM_UACCESS_H |
---|
.. | .. |
---|
25 | 22 | * perform such accesses (eg, via list poison values) which could then |
---|
26 | 23 | * be exploited for priviledge escalation. |
---|
27 | 24 | */ |
---|
28 | | -static inline unsigned int uaccess_save_and_enable(void) |
---|
| 25 | +static __always_inline unsigned int uaccess_save_and_enable(void) |
---|
29 | 26 | { |
---|
30 | 27 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN |
---|
31 | 28 | unsigned int old_domain = get_domain(); |
---|
.. | .. |
---|
40 | 37 | #endif |
---|
41 | 38 | } |
---|
42 | 39 | |
---|
43 | | -static inline void uaccess_restore(unsigned int flags) |
---|
| 40 | +static __always_inline void uaccess_restore(unsigned int flags) |
---|
44 | 41 | { |
---|
45 | 42 | #ifdef CONFIG_CPU_SW_DOMAIN_PAN |
---|
46 | 43 | /* Restore the user access mask */ |
---|
.. | .. |
---|
59 | 56 | * Note that this is actually 0x1,0000,0000 |
---|
60 | 57 | */ |
---|
61 | 58 | #define KERNEL_DS 0x00000000 |
---|
62 | | -#define get_ds() (KERNEL_DS) |
---|
63 | 59 | |
---|
64 | 60 | #ifdef CONFIG_MMU |
---|
65 | 61 | |
---|
.. | .. |
---|
80 | 76 | modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); |
---|
81 | 77 | } |
---|
82 | 78 | |
---|
83 | | -#define segment_eq(a, b) ((a) == (b)) |
---|
| 79 | +#define uaccess_kernel() (get_fs() == KERNEL_DS) |
---|
84 | 80 | |
---|
85 | | -/* We use 33-bit arithmetic here... */ |
---|
| 81 | +/* |
---|
| 82 | + * We use 33-bit arithmetic here. Success returns zero, failure returns |
---|
| 83 | + * addr_limit. We take advantage that addr_limit will be zero for KERNEL_DS, |
---|
| 84 | + * so this will always return success in that case. |
---|
| 85 | + */ |
---|
86 | 86 | #define __range_ok(addr, size) ({ \ |
---|
87 | 87 | unsigned long flag, roksum; \ |
---|
88 | 88 | __chk_user_ptr(addr); \ |
---|
89 | | - __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \ |
---|
| 89 | + __asm__(".syntax unified\n" \ |
---|
| 90 | + "adds %1, %2, %3; sbcscc %1, %1, %0; movcc %0, #0" \ |
---|
90 | 91 | : "=&r" (flag), "=&r" (roksum) \ |
---|
91 | 92 | : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \ |
---|
92 | 93 | : "cc"); \ |
---|
.. | .. |
---|
112 | 113 | unsigned long tmp; |
---|
113 | 114 | |
---|
114 | 115 | asm volatile( |
---|
| 116 | + " .syntax unified\n" |
---|
115 | 117 | " sub %1, %3, #1\n" |
---|
116 | 118 | " subs %1, %1, %0\n" |
---|
117 | 119 | " addhs %1, %1, #1\n" |
---|
118 | | - " subhss %1, %1, %2\n" |
---|
| 120 | + " subshs %1, %1, %2\n" |
---|
119 | 121 | " movlo %0, #0\n" |
---|
120 | 122 | : "+r" (safe_ptr), "=&r" (tmp) |
---|
121 | 123 | : "r" (size), "r" (current_thread_info()->addr_limit) |
---|
.. | .. |
---|
198 | 200 | register unsigned long __l asm("r1") = __limit; \ |
---|
199 | 201 | register int __e asm("r0"); \ |
---|
200 | 202 | unsigned int __ua_flags = uaccess_save_and_enable(); \ |
---|
| 203 | + int __tmp_e; \ |
---|
201 | 204 | switch (sizeof(*(__p))) { \ |
---|
202 | 205 | case 1: \ |
---|
203 | 206 | if (sizeof((x)) >= 8) \ |
---|
.. | .. |
---|
225 | 228 | break; \ |
---|
226 | 229 | default: __e = __get_user_bad(); break; \ |
---|
227 | 230 | } \ |
---|
| 231 | + __tmp_e = __e; \ |
---|
228 | 232 | uaccess_restore(__ua_flags); \ |
---|
229 | 233 | x = (typeof(*(p))) __r2; \ |
---|
230 | | - __e; \ |
---|
| 234 | + __tmp_e; \ |
---|
231 | 235 | }) |
---|
232 | 236 | |
---|
233 | 237 | #define get_user(x, p) \ |
---|
.. | .. |
---|
265 | 269 | */ |
---|
266 | 270 | #define USER_DS KERNEL_DS |
---|
267 | 271 | |
---|
268 | | -#define segment_eq(a, b) (1) |
---|
| 272 | +#define uaccess_kernel() (true) |
---|
269 | 273 | #define __addr_ok(addr) ((void)(addr), 1) |
---|
270 | 274 | #define __range_ok(addr, size) ((void)(addr), 0) |
---|
271 | 275 | #define get_fs() (KERNEL_DS) |
---|
.. | .. |
---|
279 | 283 | |
---|
280 | 284 | #endif /* CONFIG_MMU */ |
---|
281 | 285 | |
---|
282 | | -#define access_ok(type, addr, size) (__range_ok(addr, size) == 0) |
---|
| 286 | +#define access_ok(addr, size) (__range_ok(addr, size) == 0) |
---|
283 | 287 | |
---|
284 | 288 | #define user_addr_max() \ |
---|
285 | 289 | (uaccess_kernel() ? ~0UL : get_fs()) |
---|
.. | .. |
---|
578 | 582 | |
---|
579 | 583 | static inline unsigned long __must_check clear_user(void __user *to, unsigned long n) |
---|
580 | 584 | { |
---|
581 | | - if (access_ok(VERIFY_WRITE, to, n)) |
---|
| 585 | + if (access_ok(to, n)) |
---|
582 | 586 | n = __clear_user(to, n); |
---|
583 | 587 | return n; |
---|
584 | 588 | } |
---|