With the introduction of PTRACE_EVENT_XXX flags during the 2.5 development cycle it became possible for ptrace to write arbitrary data to alpha kernel stack frames because it was assumed that wherever ptrace_stop was called both a pt_regs and a switch_stack were saved upon the stack. The introduction of TIF_ALLREGS_SAVED removed the assumption that switch_stack was saved on the kernel thread by transforming the problem into a lesser bug where the access simply don't work. Saving struct switch_stack has to happen on the lowest level of the stack on alpha because it contains caller saved registers, which will be saved by the C code in arbitrary locations on the stack if the data is not saved immediately. Update kernel threads to save a full set of userspace registers on the stack so that io_uring threads can be ptraced. Update fork, vfork, clone, exit, exit_group, execve, and execveat to save all of the userspace registers when the are called as there are known PTRACE_EVENT_XXX ptrace stop points in those functions where registers can be manipulated. The switch_stack frames serve double duty in fork, vfork, and clone, as both the the childs inputs to alpha_switch_to, and the parents saved copy of the registers for debuggers to modify. This changes marks the the frame is present in the parent, and clears TIF_ALLREGS_SAVED in the child as alpha_switch_to will consume the switch_stack when the child is started. Cc: stable@xxxxxxxxxxxxxxx Inspired-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> Fixes: dbe1bdbb39db ("io_uring: handle signals for IO threads like a normal thread") Fixes: 45c1a159b85b ("Add PTRACE_O_TRACEVFORKDONE and PTRACE_O_TRACEEXIT facilities.") Fixes: a0691b116f6a ("Add new ptrace event tracing mechanism") History-tree: https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git Signed-off-by: "Eric W. Biederman" <ebiederm@xxxxxxxxxxxx> --- arch/alpha/kernel/entry.S | 24 +++++++++++++++++------- arch/alpha/kernel/process.c | 3 +++ arch/alpha/kernel/syscalls/syscall.tbl | 8 ++++---- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index c1edf54dc035..f29a40e2daf1 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -801,13 +801,18 @@ ret_from_fork: .align 4 .globl ret_from_kernel_thread .ent ret_from_kernel_thread + .cfi_startproc ret_from_kernel_thread: mov $17, $16 jsr $26, schedule_tail + /* PF_IO_WORKER threads can be ptraced */ + SAVE_SWITCH_STACK mov $9, $27 mov $10, $16 jsr $26, ($9) + RESTORE_SWITCH_STACK br $31, ret_to_user + .cfi_endproc .end ret_from_kernel_thread @@ -816,23 +821,28 @@ ret_from_kernel_thread: * have to play switch_stack games. */ -.macro fork_like name +.macro allregs name .align 4 .globl alpha_\name .ent alpha_\name + .cfi_startproc alpha_\name: .prologue 0 - bsr $1, do_switch_stack + SAVE_SWITCH_STACK jsr $26, sys_\name - ldq $26, 56($sp) - lda $sp, SWITCH_STACK_SIZE($sp) + RESTORE_SWITCH_STACK ret + .cfi_endproc .end alpha_\name .endm -fork_like fork -fork_like vfork -fork_like clone +allregs fork +allregs vfork +allregs clone +allregs exit +allregs exit_group +allregs execve +allregs execveat .macro sigreturn_like name .align 4 diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 5112ab996394..3bf480468a89 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -249,6 +249,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childti->pcb.ksp = (unsigned long) childstack; childti->pcb.flags = 1; /* set FEN, clear everything else */ + /* In the child the registers are consumed by alpha_switch_to */ + clear_ti_thread_flag(childti, TIF_ALLREGS_SAVED); + if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { /* kernel thread */ memset(childstack, 0, diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl index 3000a2e8ee21..5f85f3c11ed4 100644 --- a/arch/alpha/kernel/syscalls/syscall.tbl +++ b/arch/alpha/kernel/syscalls/syscall.tbl @@ -8,7 +8,7 @@ # The <abi> is always "common" for this file # 0 common osf_syscall alpha_syscall_zero -1 common exit sys_exit +1 common exit alpha_exit 2 common fork alpha_fork 3 common read sys_read 4 common write sys_write @@ -65,7 +65,7 @@ 56 common osf_revoke sys_ni_syscall 57 common symlink sys_symlink 58 common readlink sys_readlink -59 common execve sys_execve +59 common execve alpha_execve 60 common umask sys_umask 61 common chroot sys_chroot 62 common osf_old_fstat sys_ni_syscall @@ -333,7 +333,7 @@ 400 common io_getevents sys_io_getevents 401 common io_submit sys_io_submit 402 common io_cancel sys_io_cancel -405 common exit_group sys_exit_group +405 common exit_group alpha_exit_group 406 common lookup_dcookie sys_lookup_dcookie 407 common epoll_create sys_epoll_create 408 common epoll_ctl sys_epoll_ctl @@ -441,7 +441,7 @@ 510 common renameat2 sys_renameat2 511 common getrandom sys_getrandom 512 common memfd_create sys_memfd_create -513 common execveat sys_execveat +513 common execveat alpha_execveat 514 common seccomp sys_seccomp 515 common bpf sys_bpf 516 common userfaultfd sys_userfaultfd -- 2.20.1