| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Based on arch/arm/include/asm/uaccess.h |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2012 ARM Ltd. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License |
|---|
| 16 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | 6 | */ |
|---|
| 18 | 7 | #ifndef __ASM_UACCESS_H |
|---|
| 19 | 8 | #define __ASM_UACCESS_H |
|---|
| .. | .. |
|---|
| 30 | 19 | #include <linux/string.h> |
|---|
| 31 | 20 | |
|---|
| 32 | 21 | #include <asm/cpufeature.h> |
|---|
| 22 | +#include <asm/mmu.h> |
|---|
| 23 | +#include <asm/mte.h> |
|---|
| 33 | 24 | #include <asm/ptrace.h> |
|---|
| 34 | 25 | #include <asm/memory.h> |
|---|
| 35 | | -#include <asm/compiler.h> |
|---|
| 36 | 26 | #include <asm/extable.h> |
|---|
| 37 | 27 | |
|---|
| 38 | | -#define get_ds() (KERNEL_DS) |
|---|
| 28 | +#define HAVE_GET_KERNEL_NOFAULT |
|---|
| 29 | + |
|---|
| 39 | 30 | #define get_fs() (current_thread_info()->addr_limit) |
|---|
| 40 | 31 | |
|---|
| 41 | 32 | static inline void set_fs(mm_segment_t fs) |
|---|
| .. | .. |
|---|
| 46 | 37 | * Prevent a mispredicted conditional call to set_fs from forwarding |
|---|
| 47 | 38 | * the wrong address limit to access_ok under speculation. |
|---|
| 48 | 39 | */ |
|---|
| 49 | | - dsb(nsh); |
|---|
| 50 | | - isb(); |
|---|
| 40 | + spec_bar(); |
|---|
| 51 | 41 | |
|---|
| 52 | 42 | /* On user-mode return, check fs is correct */ |
|---|
| 53 | 43 | set_thread_flag(TIF_FSCHECK); |
|---|
| .. | .. |
|---|
| 63 | 53 | CONFIG_ARM64_UAO)); |
|---|
| 64 | 54 | } |
|---|
| 65 | 55 | |
|---|
| 66 | | -#define segment_eq(a, b) ((a) == (b)) |
|---|
| 56 | +#define uaccess_kernel() (get_fs() == KERNEL_DS) |
|---|
| 67 | 57 | |
|---|
| 68 | 58 | /* |
|---|
| 69 | 59 | * Test whether a block of memory is a valid user space address. |
|---|
| .. | .. |
|---|
| 106 | 96 | return ret; |
|---|
| 107 | 97 | } |
|---|
| 108 | 98 | |
|---|
| 109 | | -#define access_ok(type, addr, size) __range_ok(addr, size) |
|---|
| 99 | +#define access_ok(addr, size) __range_ok(addr, size) |
|---|
| 110 | 100 | #define user_addr_max get_fs |
|---|
| 111 | 101 | |
|---|
| 112 | 102 | #define _ASM_EXTABLE(from, to) \ |
|---|
| .. | .. |
|---|
| 126 | 116 | local_irq_save(flags); |
|---|
| 127 | 117 | ttbr = read_sysreg(ttbr1_el1); |
|---|
| 128 | 118 | ttbr &= ~TTBR_ASID_MASK; |
|---|
| 129 | | - /* reserved_ttbr0 placed before swapper_pg_dir */ |
|---|
| 130 | | - write_sysreg(ttbr - RESERVED_TTBR0_SIZE, ttbr0_el1); |
|---|
| 119 | + /* reserved_pg_dir placed before swapper_pg_dir */ |
|---|
| 120 | + write_sysreg(ttbr - PAGE_SIZE, ttbr0_el1); |
|---|
| 131 | 121 | isb(); |
|---|
| 132 | 122 | /* Set reserved ASID */ |
|---|
| 133 | 123 | write_sysreg(ttbr, ttbr1_el1); |
|---|
| .. | .. |
|---|
| 213 | 203 | CONFIG_ARM64_PAN)); \ |
|---|
| 214 | 204 | } while (0) |
|---|
| 215 | 205 | |
|---|
| 216 | | -static inline void uaccess_disable(void) |
|---|
| 206 | +/* |
|---|
| 207 | + * The Tag Check Flag (TCF) mode for MTE is per EL, hence TCF0 |
|---|
| 208 | + * affects EL0 and TCF affects EL1 irrespective of which TTBR is |
|---|
| 209 | + * used. |
|---|
| 210 | + * The kernel accesses TTBR0 usually with LDTR/STTR instructions |
|---|
| 211 | + * when UAO is available, so these would act as EL0 accesses using |
|---|
| 212 | + * TCF0. |
|---|
| 213 | + * However futex.h code uses exclusives which would be executed as |
|---|
| 214 | + * EL1, this can potentially cause a tag check fault even if the |
|---|
| 215 | + * user disables TCF0. |
|---|
| 216 | + * |
|---|
| 217 | + * To address the problem we set the PSTATE.TCO bit in uaccess_enable() |
|---|
| 218 | + * and reset it in uaccess_disable(). |
|---|
| 219 | + * |
|---|
| 220 | + * The Tag check override (TCO) bit disables temporarily the tag checking |
|---|
| 221 | + * preventing the issue. |
|---|
| 222 | + */ |
|---|
| 223 | +static inline void __uaccess_disable_tco(void) |
|---|
| 217 | 224 | { |
|---|
| 225 | + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(0), |
|---|
| 226 | + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); |
|---|
| 227 | +} |
|---|
| 228 | + |
|---|
| 229 | +static inline void __uaccess_enable_tco(void) |
|---|
| 230 | +{ |
|---|
| 231 | + asm volatile(ALTERNATIVE("nop", SET_PSTATE_TCO(1), |
|---|
| 232 | + ARM64_MTE, CONFIG_KASAN_HW_TAGS)); |
|---|
| 233 | +} |
|---|
| 234 | + |
|---|
| 235 | +/* |
|---|
| 236 | + * These functions disable tag checking only if in MTE async mode |
|---|
| 237 | + * since the sync mode generates exceptions synchronously and the |
|---|
| 238 | + * nofault or load_unaligned_zeropad can handle them. |
|---|
| 239 | + */ |
|---|
| 240 | +static inline void __uaccess_disable_tco_async(void) |
|---|
| 241 | +{ |
|---|
| 242 | + if (system_uses_mte_async_mode()) |
|---|
| 243 | + __uaccess_disable_tco(); |
|---|
| 244 | +} |
|---|
| 245 | + |
|---|
| 246 | +static inline void __uaccess_enable_tco_async(void) |
|---|
| 247 | +{ |
|---|
| 248 | + if (system_uses_mte_async_mode()) |
|---|
| 249 | + __uaccess_enable_tco(); |
|---|
| 250 | +} |
|---|
| 251 | + |
|---|
| 252 | +static inline void uaccess_disable_privileged(void) |
|---|
| 253 | +{ |
|---|
| 254 | + __uaccess_disable_tco(); |
|---|
| 255 | + |
|---|
| 218 | 256 | __uaccess_disable(ARM64_HAS_PAN); |
|---|
| 219 | 257 | } |
|---|
| 220 | 258 | |
|---|
| 221 | | -static inline void uaccess_enable(void) |
|---|
| 259 | +static inline void uaccess_enable_privileged(void) |
|---|
| 222 | 260 | { |
|---|
| 261 | + __uaccess_enable_tco(); |
|---|
| 262 | + |
|---|
| 223 | 263 | __uaccess_enable(ARM64_HAS_PAN); |
|---|
| 224 | 264 | } |
|---|
| 225 | 265 | |
|---|
| .. | .. |
|---|
| 266 | 306 | * The "__xxx_error" versions set the third argument to -EFAULT if an error |
|---|
| 267 | 307 | * occurs, and leave it unchanged on success. |
|---|
| 268 | 308 | */ |
|---|
| 269 | | -#define __get_user_asm(instr, alt_instr, reg, x, addr, err, feature) \ |
|---|
| 309 | +#define __get_mem_asm(load, reg, x, addr, err) \ |
|---|
| 270 | 310 | asm volatile( \ |
|---|
| 271 | | - "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \ |
|---|
| 272 | | - alt_instr " " reg "1, [%2]\n", feature) \ |
|---|
| 311 | + "1: " load " " reg "1, [%2]\n" \ |
|---|
| 273 | 312 | "2:\n" \ |
|---|
| 274 | 313 | " .section .fixup, \"ax\"\n" \ |
|---|
| 275 | 314 | " .align 2\n" \ |
|---|
| .. | .. |
|---|
| 281 | 320 | : "+r" (err), "=&r" (x) \ |
|---|
| 282 | 321 | : "r" (addr), "i" (-EFAULT)) |
|---|
| 283 | 322 | |
|---|
| 284 | | -#define __get_user_err(x, ptr, err) \ |
|---|
| 323 | +#define __raw_get_mem(ldr, x, ptr, err) \ |
|---|
| 285 | 324 | do { \ |
|---|
| 286 | 325 | unsigned long __gu_val; \ |
|---|
| 287 | | - __chk_user_ptr(ptr); \ |
|---|
| 288 | | - uaccess_enable_not_uao(); \ |
|---|
| 289 | 326 | switch (sizeof(*(ptr))) { \ |
|---|
| 290 | 327 | case 1: \ |
|---|
| 291 | | - __get_user_asm("ldrb", "ldtrb", "%w", __gu_val, (ptr), \ |
|---|
| 292 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 328 | + __get_mem_asm(ldr "b", "%w", __gu_val, (ptr), (err)); \ |
|---|
| 293 | 329 | break; \ |
|---|
| 294 | 330 | case 2: \ |
|---|
| 295 | | - __get_user_asm("ldrh", "ldtrh", "%w", __gu_val, (ptr), \ |
|---|
| 296 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 331 | + __get_mem_asm(ldr "h", "%w", __gu_val, (ptr), (err)); \ |
|---|
| 297 | 332 | break; \ |
|---|
| 298 | 333 | case 4: \ |
|---|
| 299 | | - __get_user_asm("ldr", "ldtr", "%w", __gu_val, (ptr), \ |
|---|
| 300 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 334 | + __get_mem_asm(ldr, "%w", __gu_val, (ptr), (err)); \ |
|---|
| 301 | 335 | break; \ |
|---|
| 302 | 336 | case 8: \ |
|---|
| 303 | | - __get_user_asm("ldr", "ldtr", "%x", __gu_val, (ptr), \ |
|---|
| 304 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 337 | + __get_mem_asm(ldr, "%x", __gu_val, (ptr), (err)); \ |
|---|
| 305 | 338 | break; \ |
|---|
| 306 | 339 | default: \ |
|---|
| 307 | 340 | BUILD_BUG(); \ |
|---|
| 308 | 341 | } \ |
|---|
| 309 | | - uaccess_disable_not_uao(); \ |
|---|
| 310 | 342 | (x) = (__force __typeof__(*(ptr)))__gu_val; \ |
|---|
| 311 | 343 | } while (0) |
|---|
| 312 | 344 | |
|---|
| 313 | | -#define __get_user_check(x, ptr, err) \ |
|---|
| 314 | | -({ \ |
|---|
| 315 | | - __typeof__(*(ptr)) __user *__p = (ptr); \ |
|---|
| 316 | | - might_fault(); \ |
|---|
| 317 | | - if (access_ok(VERIFY_READ, __p, sizeof(*__p))) { \ |
|---|
| 318 | | - __p = uaccess_mask_ptr(__p); \ |
|---|
| 319 | | - __get_user_err((x), __p, (err)); \ |
|---|
| 320 | | - } else { \ |
|---|
| 321 | | - (x) = 0; (err) = -EFAULT; \ |
|---|
| 322 | | - } \ |
|---|
| 323 | | -}) |
|---|
| 345 | +/* |
|---|
| 346 | + * We must not call into the scheduler between uaccess_enable_not_uao() and |
|---|
| 347 | + * uaccess_disable_not_uao(). As `x` and `ptr` could contain blocking functions, |
|---|
| 348 | + * we must evaluate these outside of the critical section. |
|---|
| 349 | + */ |
|---|
| 350 | +#define __raw_get_user(x, ptr, err) \ |
|---|
| 351 | +do { \ |
|---|
| 352 | + __typeof__(*(ptr)) __user *__rgu_ptr = (ptr); \ |
|---|
| 353 | + __typeof__(x) __rgu_val; \ |
|---|
| 354 | + __chk_user_ptr(ptr); \ |
|---|
| 355 | + \ |
|---|
| 356 | + uaccess_enable_not_uao(); \ |
|---|
| 357 | + __raw_get_mem("ldtr", __rgu_val, __rgu_ptr, err); \ |
|---|
| 358 | + uaccess_disable_not_uao(); \ |
|---|
| 359 | + \ |
|---|
| 360 | + (x) = __rgu_val; \ |
|---|
| 361 | +} while (0) |
|---|
| 324 | 362 | |
|---|
| 325 | 363 | #define __get_user_error(x, ptr, err) \ |
|---|
| 326 | | -({ \ |
|---|
| 327 | | - __get_user_check((x), (ptr), (err)); \ |
|---|
| 328 | | - (void)0; \ |
|---|
| 329 | | -}) |
|---|
| 364 | +do { \ |
|---|
| 365 | + __typeof__(*(ptr)) __user *__p = (ptr); \ |
|---|
| 366 | + might_fault(); \ |
|---|
| 367 | + if (access_ok(__p, sizeof(*__p))) { \ |
|---|
| 368 | + __p = uaccess_mask_ptr(__p); \ |
|---|
| 369 | + __raw_get_user((x), __p, (err)); \ |
|---|
| 370 | + } else { \ |
|---|
| 371 | + (x) = (__force __typeof__(x))0; (err) = -EFAULT; \ |
|---|
| 372 | + } \ |
|---|
| 373 | +} while (0) |
|---|
| 330 | 374 | |
|---|
| 331 | 375 | #define __get_user(x, ptr) \ |
|---|
| 332 | 376 | ({ \ |
|---|
| 333 | 377 | int __gu_err = 0; \ |
|---|
| 334 | | - __get_user_check((x), (ptr), __gu_err); \ |
|---|
| 378 | + __get_user_error((x), (ptr), __gu_err); \ |
|---|
| 335 | 379 | __gu_err; \ |
|---|
| 336 | 380 | }) |
|---|
| 337 | 381 | |
|---|
| 338 | 382 | #define get_user __get_user |
|---|
| 339 | 383 | |
|---|
| 340 | | -#define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature) \ |
|---|
| 384 | +/* |
|---|
| 385 | + * We must not call into the scheduler between __uaccess_enable_tco_async() and |
|---|
| 386 | + * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking |
|---|
| 387 | + * functions, we must evaluate these outside of the critical section. |
|---|
| 388 | + */ |
|---|
| 389 | +#define __get_kernel_nofault(dst, src, type, err_label) \ |
|---|
| 390 | +do { \ |
|---|
| 391 | + __typeof__(dst) __gkn_dst = (dst); \ |
|---|
| 392 | + __typeof__(src) __gkn_src = (src); \ |
|---|
| 393 | + int __gkn_err = 0; \ |
|---|
| 394 | + \ |
|---|
| 395 | + __uaccess_enable_tco_async(); \ |
|---|
| 396 | + __raw_get_mem("ldr", *((type *)(__gkn_dst)), \ |
|---|
| 397 | + (__force type *)(__gkn_src), __gkn_err); \ |
|---|
| 398 | + __uaccess_disable_tco_async(); \ |
|---|
| 399 | + \ |
|---|
| 400 | + if (unlikely(__gkn_err)) \ |
|---|
| 401 | + goto err_label; \ |
|---|
| 402 | +} while (0) |
|---|
| 403 | + |
|---|
| 404 | +#define __put_mem_asm(store, reg, x, addr, err) \ |
|---|
| 341 | 405 | asm volatile( \ |
|---|
| 342 | | - "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \ |
|---|
| 343 | | - alt_instr " " reg "1, [%2]\n", feature) \ |
|---|
| 406 | + "1: " store " " reg "1, [%2]\n" \ |
|---|
| 344 | 407 | "2:\n" \ |
|---|
| 345 | 408 | " .section .fixup,\"ax\"\n" \ |
|---|
| 346 | 409 | " .align 2\n" \ |
|---|
| .. | .. |
|---|
| 351 | 414 | : "+r" (err) \ |
|---|
| 352 | 415 | : "r" (x), "r" (addr), "i" (-EFAULT)) |
|---|
| 353 | 416 | |
|---|
| 354 | | -#define __put_user_err(x, ptr, err) \ |
|---|
| 417 | +#define __raw_put_mem(str, x, ptr, err) \ |
|---|
| 355 | 418 | do { \ |
|---|
| 356 | 419 | __typeof__(*(ptr)) __pu_val = (x); \ |
|---|
| 357 | | - __chk_user_ptr(ptr); \ |
|---|
| 358 | | - uaccess_enable_not_uao(); \ |
|---|
| 359 | 420 | switch (sizeof(*(ptr))) { \ |
|---|
| 360 | 421 | case 1: \ |
|---|
| 361 | | - __put_user_asm("strb", "sttrb", "%w", __pu_val, (ptr), \ |
|---|
| 362 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 422 | + __put_mem_asm(str "b", "%w", __pu_val, (ptr), (err)); \ |
|---|
| 363 | 423 | break; \ |
|---|
| 364 | 424 | case 2: \ |
|---|
| 365 | | - __put_user_asm("strh", "sttrh", "%w", __pu_val, (ptr), \ |
|---|
| 366 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 425 | + __put_mem_asm(str "h", "%w", __pu_val, (ptr), (err)); \ |
|---|
| 367 | 426 | break; \ |
|---|
| 368 | 427 | case 4: \ |
|---|
| 369 | | - __put_user_asm("str", "sttr", "%w", __pu_val, (ptr), \ |
|---|
| 370 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 428 | + __put_mem_asm(str, "%w", __pu_val, (ptr), (err)); \ |
|---|
| 371 | 429 | break; \ |
|---|
| 372 | 430 | case 8: \ |
|---|
| 373 | | - __put_user_asm("str", "sttr", "%x", __pu_val, (ptr), \ |
|---|
| 374 | | - (err), ARM64_HAS_UAO); \ |
|---|
| 431 | + __put_mem_asm(str, "%x", __pu_val, (ptr), (err)); \ |
|---|
| 375 | 432 | break; \ |
|---|
| 376 | 433 | default: \ |
|---|
| 377 | 434 | BUILD_BUG(); \ |
|---|
| 378 | 435 | } \ |
|---|
| 436 | +} while (0) |
|---|
| 437 | + |
|---|
| 438 | +/* |
|---|
| 439 | + * We must not call into the scheduler between uaccess_enable_not_uao() and |
|---|
| 440 | + * uaccess_disable_not_uao(). As `x` and `ptr` could contain blocking functions, |
|---|
| 441 | + * we must evaluate these outside of the critical section. |
|---|
| 442 | + */ |
|---|
| 443 | +#define __raw_put_user(x, ptr, err) \ |
|---|
| 444 | +do { \ |
|---|
| 445 | + __typeof__(*(ptr)) __user *__rpu_ptr = (ptr); \ |
|---|
| 446 | + __typeof__(*(ptr)) __rpu_val = (x); \ |
|---|
| 447 | + __chk_user_ptr(__rpu_ptr); \ |
|---|
| 448 | + \ |
|---|
| 449 | + uaccess_enable_not_uao(); \ |
|---|
| 450 | + __raw_put_mem("sttr", __rpu_val, __rpu_ptr, err); \ |
|---|
| 379 | 451 | uaccess_disable_not_uao(); \ |
|---|
| 380 | 452 | } while (0) |
|---|
| 381 | 453 | |
|---|
| 382 | | -#define __put_user_check(x, ptr, err) \ |
|---|
| 383 | | -({ \ |
|---|
| 454 | +#define __put_user_error(x, ptr, err) \ |
|---|
| 455 | +do { \ |
|---|
| 384 | 456 | __typeof__(*(ptr)) __user *__p = (ptr); \ |
|---|
| 385 | 457 | might_fault(); \ |
|---|
| 386 | | - if (access_ok(VERIFY_WRITE, __p, sizeof(*__p))) { \ |
|---|
| 458 | + if (access_ok(__p, sizeof(*__p))) { \ |
|---|
| 387 | 459 | __p = uaccess_mask_ptr(__p); \ |
|---|
| 388 | | - __put_user_err((x), __p, (err)); \ |
|---|
| 460 | + __raw_put_user((x), __p, (err)); \ |
|---|
| 389 | 461 | } else { \ |
|---|
| 390 | 462 | (err) = -EFAULT; \ |
|---|
| 391 | 463 | } \ |
|---|
| 392 | | -}) |
|---|
| 393 | | - |
|---|
| 394 | | -#define __put_user_error(x, ptr, err) \ |
|---|
| 395 | | -({ \ |
|---|
| 396 | | - __put_user_check((x), (ptr), (err)); \ |
|---|
| 397 | | - (void)0; \ |
|---|
| 398 | | -}) |
|---|
| 464 | +} while (0) |
|---|
| 399 | 465 | |
|---|
| 400 | 466 | #define __put_user(x, ptr) \ |
|---|
| 401 | 467 | ({ \ |
|---|
| 402 | 468 | int __pu_err = 0; \ |
|---|
| 403 | | - __put_user_check((x), (ptr), __pu_err); \ |
|---|
| 469 | + __put_user_error((x), (ptr), __pu_err); \ |
|---|
| 404 | 470 | __pu_err; \ |
|---|
| 405 | 471 | }) |
|---|
| 406 | 472 | |
|---|
| 407 | 473 | #define put_user __put_user |
|---|
| 408 | 474 | |
|---|
| 475 | +/* |
|---|
| 476 | + * We must not call into the scheduler between __uaccess_enable_tco_async() and |
|---|
| 477 | + * __uaccess_disable_tco_async(). As `dst` and `src` may contain blocking |
|---|
| 478 | + * functions, we must evaluate these outside of the critical section. |
|---|
| 479 | + */ |
|---|
| 480 | +#define __put_kernel_nofault(dst, src, type, err_label) \ |
|---|
| 481 | +do { \ |
|---|
| 482 | + __typeof__(dst) __pkn_dst = (dst); \ |
|---|
| 483 | + __typeof__(src) __pkn_src = (src); \ |
|---|
| 484 | + int __pkn_err = 0; \ |
|---|
| 485 | + \ |
|---|
| 486 | + __uaccess_enable_tco_async(); \ |
|---|
| 487 | + __raw_put_mem("str", *((type *)(__pkn_src)), \ |
|---|
| 488 | + (__force type *)(__pkn_dst), __pkn_err); \ |
|---|
| 489 | + __uaccess_disable_tco_async(); \ |
|---|
| 490 | + \ |
|---|
| 491 | + if (unlikely(__pkn_err)) \ |
|---|
| 492 | + goto err_label; \ |
|---|
| 493 | +} while(0) |
|---|
| 494 | + |
|---|
| 409 | 495 | extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n); |
|---|
| 410 | 496 | #define raw_copy_from_user(to, from, n) \ |
|---|
| 411 | 497 | ({ \ |
|---|
| 412 | | - __arch_copy_from_user((to), __uaccess_mask_ptr(from), (n)); \ |
|---|
| 498 | + unsigned long __acfu_ret; \ |
|---|
| 499 | + uaccess_enable_not_uao(); \ |
|---|
| 500 | + __acfu_ret = __arch_copy_from_user((to), \ |
|---|
| 501 | + __uaccess_mask_ptr(from), (n)); \ |
|---|
| 502 | + uaccess_disable_not_uao(); \ |
|---|
| 503 | + __acfu_ret; \ |
|---|
| 413 | 504 | }) |
|---|
| 414 | 505 | |
|---|
| 415 | 506 | extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n); |
|---|
| 416 | 507 | #define raw_copy_to_user(to, from, n) \ |
|---|
| 417 | 508 | ({ \ |
|---|
| 418 | | - __arch_copy_to_user(__uaccess_mask_ptr(to), (from), (n)); \ |
|---|
| 509 | + unsigned long __actu_ret; \ |
|---|
| 510 | + uaccess_enable_not_uao(); \ |
|---|
| 511 | + __actu_ret = __arch_copy_to_user(__uaccess_mask_ptr(to), \ |
|---|
| 512 | + (from), (n)); \ |
|---|
| 513 | + uaccess_disable_not_uao(); \ |
|---|
| 514 | + __actu_ret; \ |
|---|
| 419 | 515 | }) |
|---|
| 420 | 516 | |
|---|
| 421 | 517 | extern unsigned long __must_check __arch_copy_in_user(void __user *to, const void __user *from, unsigned long n); |
|---|
| 422 | 518 | #define raw_copy_in_user(to, from, n) \ |
|---|
| 423 | 519 | ({ \ |
|---|
| 424 | | - __arch_copy_in_user(__uaccess_mask_ptr(to), \ |
|---|
| 425 | | - __uaccess_mask_ptr(from), (n)); \ |
|---|
| 520 | + unsigned long __aciu_ret; \ |
|---|
| 521 | + uaccess_enable_not_uao(); \ |
|---|
| 522 | + __aciu_ret = __arch_copy_in_user(__uaccess_mask_ptr(to), \ |
|---|
| 523 | + __uaccess_mask_ptr(from), (n)); \ |
|---|
| 524 | + uaccess_disable_not_uao(); \ |
|---|
| 525 | + __aciu_ret; \ |
|---|
| 426 | 526 | }) |
|---|
| 427 | 527 | |
|---|
| 428 | 528 | #define INLINE_COPY_TO_USER |
|---|
| .. | .. |
|---|
| 431 | 531 | extern unsigned long __must_check __arch_clear_user(void __user *to, unsigned long n); |
|---|
| 432 | 532 | static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n) |
|---|
| 433 | 533 | { |
|---|
| 434 | | - if (access_ok(VERIFY_WRITE, to, n)) |
|---|
| 534 | + if (access_ok(to, n)) { |
|---|
| 535 | + uaccess_enable_not_uao(); |
|---|
| 435 | 536 | n = __arch_clear_user(__uaccess_mask_ptr(to), n); |
|---|
| 537 | + uaccess_disable_not_uao(); |
|---|
| 538 | + } |
|---|
| 436 | 539 | return n; |
|---|
| 437 | 540 | } |
|---|
| 438 | 541 | #define clear_user __clear_user |
|---|