Kernel: Implement new ptrace function PT_PEEKBUF

This enables the tracer to copy large amounts of data in a much saner
way.
This commit is contained in:
Ben Wiederhake 2021-11-25 22:55:12 +01:00 committed by Andreas Kling
parent 3e223185b3
commit 0f8483f09c
Notes: sideshowbarker 2024-07-17 23:07:51 +09:00
4 changed files with 35 additions and 0 deletions

View file

@ -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

View file

@ -458,6 +458,10 @@ struct SC_stat_params {
int follow_symlinks;
};
struct SC_ptrace_buf_params {
MutableBufferArgument<u8, size_t> buf;
};
struct SC_ptrace_params {
int request;
pid_t tid;

View file

@ -481,6 +481,7 @@ public:
m_wait_for_tracer_at_next_execve = val;
}
ErrorOr<void> peek_user_data(Span<u8> destination, Userspace<const u8*> address);
ErrorOr<FlatPtr> peek_user_data(Userspace<const FlatPtr*> address);
ErrorOr<void> poke_user_data(Userspace<FlatPtr*> address, FlatPtr data);

View file

@ -123,6 +123,24 @@ static ErrorOr<FlatPtr> handle_ptrace(const Kernel::Syscall::SC_ptrace_params& p
TRY(peer->process().poke_user_data(Userspace<FlatPtr*> { (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<Kernel::Syscall::SC_ptrace_buf_params*>(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<u8, PAGE_SIZE> 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<const u8*> { 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<uintptr_t>(params.addr)));
TRY(copy_to_user((FlatPtr*)params.data, &data));
@ -168,6 +186,15 @@ ErrorOr<FlatPtr> Process::peek_user_data(Userspace<const FlatPtr*> address)
return data;
}
ErrorOr<void> Process::peek_user_data(Span<u8> destination, Userspace<const u8*> 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<void> Process::poke_user_data(Userspace<FlatPtr*> address, FlatPtr data)
{
Memory::VirtualRange range = { address.vaddr(), sizeof(FlatPtr) };