Wie funktioniert ptrace unter Linux?

Lesezeit: 6 Minuten

Benutzeravatar von daehee
dahee

Das ptrace Der Systemaufruf ermöglicht es dem Elternprozess, den angehängten Kindprozess zu inspizieren. Zum Beispiel unter Linux, strace (was mit implementiert wird ptrace Systemaufruf) kann die vom untergeordneten Prozess aufgerufenen Systemaufrufe überprüfen.

Wenn der angehängte untergeordnete Prozess einen Systemaufruf aufruft, kann der ptracing-Elternprozess benachrichtigt werden. Aber wie genau passiert das? Ich möchte die technischen Details hinter diesem Mechanismus erfahren.

Danke im Voraus.

  • man7.org/linux/man-pages/man2/ptrace.2.html ist nützlich

    – Tristan

    29. Mai 2014 um 8:07 Uhr

  • @tristan: Soweit ich weiß, möchte das OP etwas über die Mechanismen wissen, die dies ermöglichen, nicht wirklich über die Verwendung.

    – Blagovest Buyukliev

    29. Mai 2014 um 8:09 Uhr

  • @Blagovest Buyukliev: danke. das ist genau das was ich will. Ich weiß, wie man Ptrace benutzt. Ich möchte sein internes Prinzip kennen

    – Daehe

    29. Mai 2014 um 8:23 Uhr

Benutzeravatar von osgx
osgx

Wenn der angehängte untergeordnete Prozess einen Systemaufruf aufruft, kann der ptracing-Elternprozess benachrichtigt werden. Aber wie genau passiert das?

Übergeordnete Prozessaufrufe ptrace mit PTRACE_ATTACHund sein Kind ruft ptrace mit PTRACE_TRACEME Möglichkeit. Dieses Paar verbindet zwei Prozesse, indem es einige Felder darin ausfüllt task_struct (Kernel/ptrace.c: sys_ptraceKind wird haben PT_PTRACED Flagge ein ptrace Bereich struct task_structund pid des Ptracer-Prozesses als Elternteil und in ptrace_entry aufführen – __ptrace_link; Der Elternteil zeichnet die PID des Kindes auf ptraced aufführen).

Dann ruft Strace an ptrace mit PTRACE_SYSCALL Flag, um sich selbst als Syscall-Debugger zu registrieren, indem thread_flag gesetzt wird TIF_SYSCALL_TRACE in untergeordneten Prozessen struct thread_info (durch so etwas wie set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);). arch/x86/include/asm/thread_info.h:

 67 /*
 68  * thread information flags
 69  * - these are process state flags that various assembly files
 70  *   may need to access   ...*/

 75 #define TIF_SYSCALL_TRACE       0       /* syscall trace active */
 99 #define _TIF_SYSCALL_TRACE      (1 << TIF_SYSCALL_TRACE)

Bei jedem Syscall-Eintritt oder -Austritt prüft der architekturspezifische Syscall-Eintrittscode dies _TIF_SYSCALL_TRACE Flagge (direkt in der Assembler-Implementierung von syscall, zum Beispiel x86 arch/x86/kernel/entry_32.S: jnz syscall_trace_entry in ENTRY(system_call) und ähnlichen Code in syscall_exit_work), und wenn es gesetzt ist, wird Ptracer mit einem Signal (SIGTRAP) benachrichtigt und das Kind wird vorübergehend gestoppt. Dies geschieht in der Regel in syscall_trace_enter und syscall_trace_leave :

1457 long syscall_trace_enter(struct pt_regs *regs)

1483         if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) &&
1484             tracehook_report_syscall_entry(regs))
1485                 ret = -1L;

1507 void syscall_trace_leave(struct pt_regs *regs)

1531         if (step || test_thread_flag(TIF_SYSCALL_TRACE))
1532                 tracehook_report_syscall_exit(regs, step);

Das tracehook_report_syscall_* Sind echte Arbeiter hier, werden sie anrufen ptrace_report_syscall. include/linux/tracehook.h:

 80 /**
 81  * tracehook_report_syscall_entry - task is about to attempt a system call
 82  * @regs:               user register state of current task
 83  *
 84  * This will be called if %TIF_SYSCALL_TRACE has been set, when the
 85  * current task has just entered the kernel for a system call.
 86  * Full user register state is available here.  Changing the values
 87  * in @regs can affect the system call number and arguments to be tried.
 88  * It is safe to block here, preventing the system call from beginning.
 89  *
 90  * Returns zero normally, or nonzero if the calling arch code should abort
 91  * the system call.  That must prevent normal entry so no system call is
 92  * made.  If @task ever returns to user mode after this, its register state
 93  * is unspecified, but should be something harmless like an %ENOSYS error
 94  * return.  It should preserve enough information so that syscall_rollback()
 95  * can work (see asm-generic/syscall.h).
 96  *
 97  * Called without locks, just after entering kernel mode.
 98  */
 99 static inline __must_check int tracehook_report_syscall_entry(
100         struct pt_regs *regs)
101 {
102         return ptrace_report_syscall(regs);
103 }
104 
105 /**
106  * tracehook_report_syscall_exit - task has just finished a system call
107  * @regs:               user register state of current task
108  * @step:               nonzero if simulating single-step or block-step
109  *
110  * This will be called if %TIF_SYSCALL_TRACE has been set, when the
111  * current task has just finished an attempted system call.  Full
112  * user register state is available here.  It is safe to block here,
113  * preventing signals from being processed.
114  *
115  * If @step is nonzero, this report is also in lieu of the normal
116  * trap that would follow the system call instruction because
117  * user_enable_block_step() or user_enable_single_step() was used.
118  * In this case, %TIF_SYSCALL_TRACE might not be set.
119  *
120  * Called without locks, just before checking for pending signals.
121  */
122 static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step)
123 {
...
130 
131         ptrace_report_syscall(regs);
132 }

Und ptrace_report_syscall generiert SIGTRAP für Debugger oder strace über ptrace_notify/ptrace_do_notify:

 55 /*
 56  * ptrace report for syscall entry and exit looks identical.
 57  */
 58 static inline int ptrace_report_syscall(struct pt_regs *regs)
 59 {
 60         int ptrace = current->ptrace;
 61 
 62         if (!(ptrace & PT_PTRACED))
 63                 return 0;
 64 
 65         ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
 66 
 67         /*
 68          * this isn't the same as continuing with a signal, but it will do
 69          * for normal use.  strace only continues with a signal if the
 70          * stopping signal is not SIGTRAP.  -brl
 71          */
 72         if (current->exit_code) {
 73                 send_sig(current->exit_code, current, 1);
 74                 current->exit_code = 0;
 75         }
 76 
 77         return fatal_signal_pending(current);
 78 }

ptrace_notify ist implementiert in kernel/signal.cstoppt es das Kind und übergibt sig_info an ptracer:

1961 static void ptrace_do_notify(int signr, int exit_code, int why)
1962 {
1963         siginfo_t info;
1964 
1965         memset(&info, 0, sizeof info);
1966         info.si_signo = signr;
1967         info.si_code = exit_code;
1968         info.si_pid = task_pid_vnr(current);
1969         info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
1970 
1971         /* Let the debugger run.  */
1972         ptrace_stop(exit_code, why, 1, &info);
1973 }
1974 
1975 void ptrace_notify(int exit_code)
1976 {
1977         BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);
1978         if (unlikely(current->task_works))
1979                 task_work_run();
1980 
1981         spin_lock_irq(&current->sighand->siglock);
1982         ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED);
1983         spin_unlock_irq(&current->sighand->siglock);
1984 }

ptrace_stop ist im selben signal.c Datei, Zeile 1839 für 3.13.

  • genial 🙂 das ist genau die Art von Antwort, die ich wollte!

    – Daehe

    29. Mai 2014 um 9:00 Uhr

  • Was ist die Bedeutung von current->exit_code ? Was wird es verwendet? Ich untersuche derzeit ein Szenario, in dem Signale ausgelöst werden, während Ptrace an einen Prozess angehängt ist. Was macht ptrace_stop() auch? Ich sehe, dass es den exit_code sowohl setzt als auch löscht, als Ergebnis wird das Signal nicht geliefert. Bitte lassen Sie mich wissen, wenn Sie eine separate Anfrage stellen möchten. Brauche wirklich eure Hilfe. Vielen Dank.

    – Sandeep

    9. Juli 2014 um 4:41 Uhr

  • Ptrace_stop ist hier: lxr.free-electrons.com/source/kernel/signal.c?v=3.13#L1828 es ändert nur den Zustand current zu TASK_TRACED (gesehen als T in ps und top) und sendet das vorbereitete Signal auch an Eltern/Ptracer. Soweit ich weiß, ist das Feld exit_code von struct task_struct (einschließlich sched.h) wird verwendet, um das Signal vorübergehend zu speichern, damit Ptracer das Signal ändern oder löschen kann.

    – osgx

    9. Juli 2014 um 9:14 Uhr

  • Der Ptrace-Systemaufruf verwendet access_process_vm, um Daten von anderen Prozessen zu lesen. Allerdings werden die Adressräume verschiedener Prozesse isoliert, wie wird das erreicht?

    – Choxschwert

    5. Oktober 2021 um 4:16 Uhr

1391030cookie-checkWie funktioniert ptrace unter Linux?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy