Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ptrace: Remove arch_ptrace_attach

The last remaining implementation of arch_ptrace_attach is ia64's
ptrace_attach_sync_user_rbs which was added at the end of 2007 in
commit aa91a2e90044 ("[IA64] Synchronize RBS on PTRACE_ATTACH").

Reading the comments and examining the code ptrace_attach_sync_user_rbs
has the sole purpose of saving registers to the stack when ptrace_attach
changes TASK_STOPPED to TASK_TRACED. In all other cases arch_ptrace_stop
takes care of the register saving.

In commit d79fdd6d96f4 ("ptrace: Clean transitions between TASK_STOPPED and TRACED")
modified ptrace_attach to wake up the thread and enter ptrace_stop normally even
when the thread starts out stopped.

This makes ptrace_attach_sync_user_rbs completely unnecessary. So just
remove it.

I read through the code to verify that ptrace_attach_sync_user_rbs is
unnecessary. What I found is that the code is quite dead.

Reading ptrace_attach_sync_user_rbs it is easy to see that the it does
nothing unless __state == TASK_STOPPED.

Calling arch_ptrace_attach (aka ptrace_attach_sync_user_rbs) after
ptrace_traceme it is easy to see that because we are talking about the
current process the value of __state is TASK_RUNNING. Which means
ptrace_attach_sync_user_rbs does nothing.

The only other call of arch_ptrace_attach (aka
ptrace_attach_sync_user_rbs) is after ptrace_attach.

If the task is running (and PTRACE_SEIZE is not specified), a SIGSTOP
is sent which results in do_signal_stop setting JOBCTL_TRAP_STOP on
the target task (as it is ptraced) and the target task stopping
in ptrace_stop with __state == TASK_TRACED.

If the task was already stopped then ptrace_attach sets
JOBCTL_TRAPPING and JOBCTL_TRAP_STOP, wakes it out of __TASK_STOPPED,
and waits until the JOBCTL_TRAPPING_BIT is clear. At which point
the task stops in ptrace_stop.

In both cases there are a couple of funning excpetions such as if the
traced task receiveds a SIGCONT, or is set a fatal signal.

However in all of those cases the tracee never stops in __state
TASK_STOPPED. Which is a long way of saying that ptrace_attach_sync_user_rbs
is guaranteed never to do anything.

Cc: linux-ia64@vger.kernel.org
Tested-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Link: https://lkml.kernel.org/r/20220505182645.497868-4-ebiederm@xmission.com
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>

-79
-4
arch/ia64/include/asm/ptrace.h
··· 139 139 #define arch_ptrace_stop_needed() \ 140 140 (!test_thread_flag(TIF_RESTORE_RSE)) 141 141 142 - extern void ptrace_attach_sync_user_rbs (struct task_struct *); 143 - #define arch_ptrace_attach(child) \ 144 - ptrace_attach_sync_user_rbs(child) 145 - 146 142 #define arch_has_single_step() (1) 147 143 #define arch_has_block_step() (1) 148 144
-57
arch/ia64/kernel/ptrace.c
··· 618 618 } 619 619 620 620 /* 621 - * After PTRACE_ATTACH, a thread's register backing store area in user 622 - * space is assumed to contain correct data whenever the thread is 623 - * stopped. arch_ptrace_stop takes care of this on tracing stops. 624 - * But if the child was already stopped for job control when we attach 625 - * to it, then it might not ever get into ptrace_stop by the time we 626 - * want to examine the user memory containing the RBS. 627 - */ 628 - void 629 - ptrace_attach_sync_user_rbs (struct task_struct *child) 630 - { 631 - int stopped = 0; 632 - struct unw_frame_info info; 633 - 634 - /* 635 - * If the child is in TASK_STOPPED, we need to change that to 636 - * TASK_TRACED momentarily while we operate on it. This ensures 637 - * that the child won't be woken up and return to user mode while 638 - * we are doing the sync. (It can only be woken up for SIGKILL.) 639 - */ 640 - 641 - read_lock(&tasklist_lock); 642 - if (child->sighand) { 643 - spin_lock_irq(&child->sighand->siglock); 644 - if (READ_ONCE(child->__state) == TASK_STOPPED && 645 - !test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) { 646 - set_notify_resume(child); 647 - 648 - WRITE_ONCE(child->__state, TASK_TRACED); 649 - stopped = 1; 650 - } 651 - spin_unlock_irq(&child->sighand->siglock); 652 - } 653 - read_unlock(&tasklist_lock); 654 - 655 - if (!stopped) 656 - return; 657 - 658 - unw_init_from_blocked_task(&info, child); 659 - do_sync_rbs(&info, ia64_sync_user_rbs); 660 - 661 - /* 662 - * Now move the child back into TASK_STOPPED if it should be in a 663 - * job control stop, so that SIGCONT can be used to wake it up. 664 - */ 665 - read_lock(&tasklist_lock); 666 - if (child->sighand) { 667 - spin_lock_irq(&child->sighand->siglock); 668 - if (READ_ONCE(child->__state) == TASK_TRACED && 669 - (child->signal->flags & SIGNAL_STOP_STOPPED)) { 670 - WRITE_ONCE(child->__state, TASK_STOPPED); 671 - } 672 - spin_unlock_irq(&child->sighand->siglock); 673 - } 674 - read_unlock(&tasklist_lock); 675 - } 676 - 677 - /* 678 621 * Write f32-f127 back to task->thread.fph if it has been modified. 679 622 */ 680 623 inline void
-18
kernel/ptrace.c
··· 1285 1285 return ret; 1286 1286 } 1287 1287 1288 - #ifndef arch_ptrace_attach 1289 - #define arch_ptrace_attach(child) do { } while (0) 1290 - #endif 1291 - 1292 1288 SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, 1293 1289 unsigned long, data) 1294 1290 { ··· 1293 1297 1294 1298 if (request == PTRACE_TRACEME) { 1295 1299 ret = ptrace_traceme(); 1296 - if (!ret) 1297 - arch_ptrace_attach(current); 1298 1300 goto out; 1299 1301 } 1300 1302 ··· 1304 1310 1305 1311 if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { 1306 1312 ret = ptrace_attach(child, request, addr, data); 1307 - /* 1308 - * Some architectures need to do book-keeping after 1309 - * a ptrace attach. 1310 - */ 1311 - if (!ret) 1312 - arch_ptrace_attach(child); 1313 1313 goto out_put_task_struct; 1314 1314 } 1315 1315 ··· 1443 1455 1444 1456 if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { 1445 1457 ret = ptrace_attach(child, request, addr, data); 1446 - /* 1447 - * Some architectures need to do book-keeping after 1448 - * a ptrace attach. 1449 - */ 1450 - if (!ret) 1451 - arch_ptrace_attach(child); 1452 1458 goto out_put_task_struct; 1453 1459 } 1454 1460