1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 18:27:35 +00:00

Kernel: Add 'ptrace' syscall

This commit adds a basic implementation of
the ptrace syscall, which allows one process
(the tracer) to control another process (the tracee).

While a process is being traced, it is stopped whenever a signal is
received (other than SIGCONT).

The tracer can start tracing another thread with PT_ATTACH,
which causes the tracee to stop.

From there, the tracer can use PT_CONTINUE
to continue the execution of the tracee,
or use other request codes (which haven't been implemented yet)
to modify the state of the tracee.

Additional request codes are PT_SYSCALL, which causes the tracee to
continue exection but stop at the next entry or exit from a syscall,
and PT_GETREGS which fethces the last saved register set of the tracee
(can be used to inspect syscall arguments and return value).

A special request code is PT_TRACE_ME, which is issued by the tracee
and causes it to stop when it calls execve and wait for the
tracer to attach.
This commit is contained in:
Itamar 2020-03-28 11:47:16 +03:00 committed by Andreas Kling
parent c9396be83f
commit 6b74d38aab
13 changed files with 300 additions and 102 deletions

View file

@ -272,7 +272,6 @@ public:
int sys$set_thread_name(int tid, const char* buffer, size_t buffer_size);
int sys$get_thread_name(int tid, char* buffer, size_t buffer_size);
int sys$rename(const Syscall::SC_rename_params*);
int sys$systrace(pid_t);
int sys$mknod(const Syscall::SC_mknod_params*);
int sys$shbuf_create(int, void** buffer);
int sys$shbuf_allow_pid(int, pid_t peer_pid);
@ -300,6 +299,7 @@ public:
int sys$unveil(const Syscall::SC_unveil_params*);
int sys$perf_event(int type, FlatPtr arg1, FlatPtr arg2);
int sys$get_stack_bounds(FlatPtr* stack_base, size_t* stack_size);
int sys$ptrace(const Syscall::SC_ptrace_params*);
template<bool sockname, typename Params>
int get_sock_or_peer_name(const Params&);
@ -316,9 +316,6 @@ public:
const NonnullOwnPtrVector<Region>& regions() const { return m_regions; }
void dump_regions();
ProcessTracer* tracer() { return m_tracer.ptr(); }
ProcessTracer& ensure_tracer();
u32 m_ticks_in_user { 0 };
u32 m_ticks_in_kernel { 0 };
@ -442,6 +439,8 @@ private:
KResultOr<String> get_syscall_path_argument(const char* user_path, size_t path_length) const;
KResultOr<String> get_syscall_path_argument(const Syscall::StringArgument&) const;
bool has_tracee_thread(int tracer_pid) const;
RefPtr<PageDirectory> m_page_directory;
Process* m_prev { nullptr };
@ -500,8 +499,6 @@ private:
FixedArray<gid_t> m_extra_gids;
RefPtr<ProcessTracer> m_tracer;
WeakPtr<Region> m_master_tls_region;
size_t m_master_tls_size { 0 };
size_t m_master_tls_alignment { 0 };
@ -526,6 +523,11 @@ private:
OwnPtr<PerformanceEventBuffer> m_perf_event_buffer;
u32 m_inspector_count { 0 };
// This member is used in the implementation of ptrace's PT_TRACEME flag.
// If it is set to true, the process will stop at the next execve syscall
// and wait for a tracer to attach.
bool m_wait_for_tracer_at_next_execve { false };
};
class ProcessInspectionHandle {
@ -585,7 +587,7 @@ inline void Process::for_each_child(Callback callback)
pid_t my_pid = pid();
for (auto* process = g_processes->head(); process;) {
auto* next_process = process->next();
if (process->ppid() == my_pid) {
if (process->ppid() == my_pid || process->has_tracee_thread(m_pid)) {
if (callback(*process) == IterationDecision::Break)
break;
}