| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Based on arch/arm/kernel/signal.c |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 1995-2009 Russell King |
|---|
| 5 | 6 | * Copyright (C) 2012 ARM Ltd. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 18 | 7 | */ |
|---|
| 19 | 8 | |
|---|
| 20 | 9 | #include <linux/cache.h> |
|---|
| .. | .. |
|---|
| 40 | 29 | #include <asm/unistd.h> |
|---|
| 41 | 30 | #include <asm/fpsimd.h> |
|---|
| 42 | 31 | #include <asm/ptrace.h> |
|---|
| 32 | +#include <asm/syscall.h> |
|---|
| 43 | 33 | #include <asm/signal32.h> |
|---|
| 44 | 34 | #include <asm/traps.h> |
|---|
| 45 | 35 | #include <asm/vdso.h> |
|---|
| .. | .. |
|---|
| 255 | 245 | if (vq) { |
|---|
| 256 | 246 | /* |
|---|
| 257 | 247 | * This assumes that the SVE state has already been saved to |
|---|
| 258 | | - * the task struct by calling preserve_fpsimd_context(). |
|---|
| 248 | + * the task struct by calling the function |
|---|
| 249 | + * fpsimd_signal_preserve_current_state(). |
|---|
| 259 | 250 | */ |
|---|
| 260 | 251 | err |= __copy_to_user((char __user *)ctx + SVE_SIG_REGS_OFFSET, |
|---|
| 261 | 252 | current->thread.sve_state, |
|---|
| .. | .. |
|---|
| 296 | 287 | */ |
|---|
| 297 | 288 | |
|---|
| 298 | 289 | fpsimd_flush_task_state(current); |
|---|
| 299 | | - barrier(); |
|---|
| 300 | | - /* From now, fpsimd_thread_switch() won't clear TIF_FOREIGN_FPSTATE */ |
|---|
| 301 | | - |
|---|
| 302 | | - set_thread_flag(TIF_FOREIGN_FPSTATE); |
|---|
| 303 | | - barrier(); |
|---|
| 304 | 290 | /* From now, fpsimd_thread_switch() won't touch thread.sve_state */ |
|---|
| 305 | 291 | |
|---|
| 306 | 292 | sve_alloc(current); |
|---|
| .. | .. |
|---|
| 387 | 373 | goto done; |
|---|
| 388 | 374 | |
|---|
| 389 | 375 | case FPSIMD_MAGIC: |
|---|
| 376 | + if (!system_supports_fpsimd()) |
|---|
| 377 | + goto invalid; |
|---|
| 390 | 378 | if (user->fpsimd) |
|---|
| 391 | 379 | goto invalid; |
|---|
| 392 | 380 | |
|---|
| .. | .. |
|---|
| 470 | 458 | offset = 0; |
|---|
| 471 | 459 | limit = extra_size; |
|---|
| 472 | 460 | |
|---|
| 473 | | - if (!access_ok(VERIFY_READ, base, limit)) |
|---|
| 461 | + if (!access_ok(base, limit)) |
|---|
| 474 | 462 | goto invalid; |
|---|
| 475 | 463 | |
|---|
| 476 | 464 | continue; |
|---|
| .. | .. |
|---|
| 522 | 510 | if (err == 0) |
|---|
| 523 | 511 | err = parse_user_sigframe(&user, sf); |
|---|
| 524 | 512 | |
|---|
| 525 | | - if (err == 0) { |
|---|
| 513 | + if (err == 0 && system_supports_fpsimd()) { |
|---|
| 526 | 514 | if (!user.fpsimd) |
|---|
| 527 | 515 | return -EINVAL; |
|---|
| 528 | 516 | |
|---|
| .. | .. |
|---|
| 556 | 544 | |
|---|
| 557 | 545 | frame = (struct rt_sigframe __user *)regs->sp; |
|---|
| 558 | 546 | |
|---|
| 559 | | - if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) |
|---|
| 547 | + if (!access_ok(frame, sizeof (*frame))) |
|---|
| 560 | 548 | goto badframe; |
|---|
| 561 | 549 | |
|---|
| 562 | 550 | if (restore_sigframe(regs, frame)) |
|---|
| .. | .. |
|---|
| 584 | 572 | { |
|---|
| 585 | 573 | int err; |
|---|
| 586 | 574 | |
|---|
| 587 | | - err = sigframe_alloc(user, &user->fpsimd_offset, |
|---|
| 588 | | - sizeof(struct fpsimd_context)); |
|---|
| 589 | | - if (err) |
|---|
| 590 | | - return err; |
|---|
| 575 | + if (system_supports_fpsimd()) { |
|---|
| 576 | + err = sigframe_alloc(user, &user->fpsimd_offset, |
|---|
| 577 | + sizeof(struct fpsimd_context)); |
|---|
| 578 | + if (err) |
|---|
| 579 | + return err; |
|---|
| 580 | + } |
|---|
| 591 | 581 | |
|---|
| 592 | 582 | /* fault information, if valid */ |
|---|
| 593 | 583 | if (add_all || current->thread.fault_code) { |
|---|
| .. | .. |
|---|
| 639 | 629 | |
|---|
| 640 | 630 | err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); |
|---|
| 641 | 631 | |
|---|
| 642 | | - if (err == 0) { |
|---|
| 632 | + if (err == 0 && system_supports_fpsimd()) { |
|---|
| 643 | 633 | struct fpsimd_context __user *fpsimd_ctx = |
|---|
| 644 | 634 | apply_user_offset(user, user->fpsimd_offset); |
|---|
| 645 | 635 | err |= preserve_fpsimd_context(fpsimd_ctx); |
|---|
| .. | .. |
|---|
| 730 | 720 | /* |
|---|
| 731 | 721 | * Check that we can actually write to the signal frame. |
|---|
| 732 | 722 | */ |
|---|
| 733 | | - if (!access_ok(VERIFY_WRITE, user->sigframe, sp_top - sp)) |
|---|
| 723 | + if (!access_ok(user->sigframe, sp_top - sp)) |
|---|
| 734 | 724 | return -EFAULT; |
|---|
| 735 | 725 | |
|---|
| 736 | 726 | return 0; |
|---|
| .. | .. |
|---|
| 745 | 735 | regs->sp = (unsigned long)user->sigframe; |
|---|
| 746 | 736 | regs->regs[29] = (unsigned long)&user->next_frame->fp; |
|---|
| 747 | 737 | regs->pc = (unsigned long)ka->sa.sa_handler; |
|---|
| 738 | + |
|---|
| 739 | + /* |
|---|
| 740 | + * Signal delivery is a (wacky) indirect function call in |
|---|
| 741 | + * userspace, so simulate the same setting of BTYPE as a BLR |
|---|
| 742 | + * <register containing the signal handler entry point>. |
|---|
| 743 | + * Signal delivery to a location in a PROT_BTI guarded page |
|---|
| 744 | + * that is not a function entry point will now trigger a |
|---|
| 745 | + * SIGILL in userspace. |
|---|
| 746 | + * |
|---|
| 747 | + * If the signal handler entry point is not in a PROT_BTI |
|---|
| 748 | + * guarded page, this is harmless. |
|---|
| 749 | + */ |
|---|
| 750 | + if (system_supports_bti()) { |
|---|
| 751 | + regs->pstate &= ~PSR_BTYPE_MASK; |
|---|
| 752 | + regs->pstate |= PSR_BTYPE_C; |
|---|
| 753 | + } |
|---|
| 754 | + |
|---|
| 755 | + /* TCO (Tag Check Override) always cleared for signal handlers */ |
|---|
| 756 | + regs->pstate &= ~PSR_TCO_BIT; |
|---|
| 748 | 757 | |
|---|
| 749 | 758 | if (ka->sa.sa_flags & SA_RESTORER) |
|---|
| 750 | 759 | sigtramp = ka->sa.sa_restorer; |
|---|
| .. | .. |
|---|
| 884 | 893 | retval == -ERESTART_RESTARTBLOCK || |
|---|
| 885 | 894 | (retval == -ERESTARTSYS && |
|---|
| 886 | 895 | !(ksig.ka.sa.sa_flags & SA_RESTART)))) { |
|---|
| 887 | | - regs->regs[0] = -EINTR; |
|---|
| 896 | + syscall_set_return_value(current, regs, -EINTR, 0); |
|---|
| 888 | 897 | regs->pc = continue_addr; |
|---|
| 889 | 898 | } |
|---|
| 890 | 899 | |
|---|
| .. | .. |
|---|
| 908 | 917 | asmlinkage void do_notify_resume(struct pt_regs *regs, |
|---|
| 909 | 918 | unsigned long thread_flags) |
|---|
| 910 | 919 | { |
|---|
| 911 | | - /* |
|---|
| 912 | | - * The assembly code enters us with IRQs off, but it hasn't |
|---|
| 913 | | - * informed the tracing code of that for efficiency reasons. |
|---|
| 914 | | - * Update the trace code with the current status. |
|---|
| 915 | | - */ |
|---|
| 916 | | - trace_hardirqs_off(); |
|---|
| 917 | | - |
|---|
| 918 | 920 | do { |
|---|
| 919 | 921 | /* Check valid user FS if needed */ |
|---|
| 920 | 922 | addr_limit_user_check(); |
|---|
| .. | .. |
|---|
| 930 | 932 | if (thread_flags & _TIF_UPROBE) |
|---|
| 931 | 933 | uprobe_notify_resume(regs); |
|---|
| 932 | 934 | |
|---|
| 933 | | - if (thread_flags & _TIF_SIGPENDING) |
|---|
| 935 | + if (thread_flags & _TIF_MTE_ASYNC_FAULT) { |
|---|
| 936 | + clear_thread_flag(TIF_MTE_ASYNC_FAULT); |
|---|
| 937 | + send_sig_fault(SIGSEGV, SEGV_MTEAERR, |
|---|
| 938 | + (void __user *)NULL, current); |
|---|
| 939 | + } |
|---|
| 940 | + |
|---|
| 941 | + if (thread_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) |
|---|
| 934 | 942 | do_signal(regs); |
|---|
| 935 | 943 | |
|---|
| 936 | 944 | if (thread_flags & _TIF_NOTIFY_RESUME) { |
|---|
| 937 | | - clear_thread_flag(TIF_NOTIFY_RESUME); |
|---|
| 938 | 945 | tracehook_notify_resume(regs); |
|---|
| 939 | 946 | rseq_handle_notify_resume(NULL, regs); |
|---|
| 940 | 947 | } |
|---|