diff --git a/Kernel/API/POSIX/sys/ptrace.h b/Kernel/API/POSIX/sys/ptrace.h index 8b9c0c0546..c27604bf0a 100644 --- a/Kernel/API/POSIX/sys/ptrace.h +++ b/Kernel/API/POSIX/sys/ptrace.h @@ -21,8 +21,11 @@ extern "C" { #define PT_PEEK 7 #define PT_POKE 8 #define PT_SETREGS 9 + +// Serenity extensions: #define PT_POKEDEBUG 10 #define PT_PEEKDEBUG 11 +#define PT_PEEKBUF 12 #define PT_READ_I PT_PEEK #define PT_READ_D PT_PEEK diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index 63d3050e2f..bacfc5c750 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -458,6 +458,10 @@ struct SC_stat_params { int follow_symlinks; }; +struct SC_ptrace_buf_params { + MutableBufferArgument buf; +}; + struct SC_ptrace_params { int request; pid_t tid; diff --git a/Kernel/Process.h b/Kernel/Process.h index e0ac48fecc..bd668c1dfb 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -481,6 +481,7 @@ public: m_wait_for_tracer_at_next_execve = val; } + ErrorOr peek_user_data(Span destination, Userspace address); ErrorOr peek_user_data(Userspace address); ErrorOr poke_user_data(Userspace address, FlatPtr data); diff --git a/Kernel/Syscalls/ptrace.cpp b/Kernel/Syscalls/ptrace.cpp index 9547725a33..0eede17a7c 100644 --- a/Kernel/Syscalls/ptrace.cpp +++ b/Kernel/Syscalls/ptrace.cpp @@ -123,6 +123,24 @@ static ErrorOr handle_ptrace(const Kernel::Syscall::SC_ptrace_params& p TRY(peer->process().poke_user_data(Userspace { (FlatPtr)params.addr }, params.data)); return 0; + case PT_PEEKBUF: { + Kernel::Syscall::SC_ptrace_buf_params buf_params {}; + TRY(copy_from_user(&buf_params, reinterpret_cast(params.data))); + // This is a comparatively large allocation on the Kernel stack. + // However, we know that we're close to the root of the call stack, and the following calls shouldn't go too deep. + Array buf; + FlatPtr tracee_ptr = (FlatPtr)params.addr; + while (buf_params.buf.size > 0) { + size_t copy_this_iteration = min(buf.size(), buf_params.buf.size); + TRY(peer->process().peek_user_data(buf.span().slice(0, copy_this_iteration), Userspace { tracee_ptr })); + TRY(copy_to_user((void*)buf_params.buf.data, buf.data(), copy_this_iteration)); + tracee_ptr += copy_this_iteration; + buf_params.buf.data += copy_this_iteration; + buf_params.buf.size -= copy_this_iteration; + } + break; + } + case PT_PEEKDEBUG: { auto data = TRY(peer->peek_debug_register(reinterpret_cast(params.addr))); TRY(copy_to_user((FlatPtr*)params.data, &data)); @@ -168,6 +186,15 @@ ErrorOr Process::peek_user_data(Userspace address) return data; } +ErrorOr Process::peek_user_data(Span destination, Userspace address) +{ + // This function can be called from the context of another + // process that called PT_PEEKBUF + ScopedAddressSpaceSwitcher switcher(*this); + TRY(copy_from_user(destination.data(), address, destination.size())); + return {}; +} + ErrorOr Process::poke_user_data(Userspace address, FlatPtr data) { Memory::VirtualRange range = { address.vaddr(), sizeof(FlatPtr) };