| .. | .. |
|---|
| 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 | } |
|---|