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

ptrace: Add PT_POKE

PT_POKE writes a single word to the tracee's address space.

Some caveats:
- If the user requests to write to an address in a read-only region, we
temporarily change the page's protections to allow it.

- If the user requests to write to a region that's backed by a
SharedInodeVMObject, we replace the vmobject with a PrivateIndoeVMObject.
This commit is contained in:
Itamar 2020-04-05 22:58:44 +03:00 committed by Andreas Kling
parent 924fda19b0
commit b306ac9b2b
5 changed files with 52 additions and 3 deletions

View file

@ -4916,8 +4916,11 @@ int Process::sys$ptrace(const Syscall::SC_ptrace_params* user_params)
if (params.pid == m_pid)
return -EINVAL;
InterruptDisabler disabler;
auto* peer = Thread::from_tid(params.pid);
Thread* peer = nullptr;
{
InterruptDisabler disabler;
peer = Thread::from_tid(params.pid);
}
if (!peer)
return -ESRCH;
@ -4974,6 +4977,7 @@ int Process::sys$ptrace(const Syscall::SC_ptrace_params* user_params)
}
break;
}
case PT_PEEK: {
uint32_t* addr = reinterpret_cast<uint32_t*>(params.addr);
if (!MM.validate_user_read(peer->process(), VirtualAddress(addr), sizeof(uint32_t))) {
@ -4987,6 +4991,40 @@ int Process::sys$ptrace(const Syscall::SC_ptrace_params* user_params)
result = *addr;
return result;
}
case PT_POKE: {
uint32_t* addr = reinterpret_cast<uint32_t*>(params.addr);
// We validate for "read" because PT_POKE can write to readonly pages,
// as long as they are user pages
if (!MM.validate_user_read(peer->process(), VirtualAddress(addr), sizeof(uint32_t))) {
return -EFAULT;
}
ProcessPagingScope scope(peer->process());
Range range = { VirtualAddress(addr), sizeof(uint32_t) };
auto* region = peer->process().region_containing(range);
ASSERT(region != nullptr);
if (region->is_shared()) {
// If the region is shared, we change its vmobject to a PrivateInodeVMObject
// to prevent the write operation from chaning any shared inode data
ASSERT(region->vmobject().is_shared_inode());
region->set_vmobject(PrivateInodeVMObject::create_with_inode(static_cast<SharedInodeVMObject&>(region->vmobject()).inode()));
region->set_shared(false);
}
const bool was_writable = region->is_writable();
if (!was_writable) //TODO refactor into scopeguard
region->set_writable(true);
region->remap();
{
SmapDisabler dis;
*addr = params.data;
}
if (!was_writable) {
region->set_writable(false);
region->remap();
}
break;
}

View file

@ -555,3 +555,4 @@ struct rtentry {
#define PT_GETREGS 5
#define PT_DETACH 6
#define PT_PEEK 7
#define PT_POKE 8

View file

@ -31,6 +31,7 @@
#include <AK/Weakable.h>
#include <Kernel/Heap/SlabAllocator.h>
#include <Kernel/VM/RangeAllocator.h>
#include <Kernel/VM/VMObject.h>
namespace Kernel {
@ -79,6 +80,7 @@ public:
const VMObject& vmobject() const { return *m_vmobject; }
VMObject& vmobject() { return *m_vmobject; }
void set_vmobject(NonnullRefPtr<VMObject>&& obj) { m_vmobject = obj; }
bool is_shared() const { return m_shared; }
void set_shared(bool shared) { m_shared = shared; }