1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-23 18:45:07 +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

@ -122,6 +122,8 @@ VirtualAddress get_entry_point(int pid)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
// TODO: pledge & unveil
// TOOD: check that we didn't somehow hurt performance. boot seems slower? (or it's just laptop battey)
if (argc == 1) if (argc == 1)
return usage(); return usage();
@ -157,7 +159,12 @@ int main(int argc, char** argv)
printf("eip:0x%x\n", regs.eip); printf("eip:0x%x\n", regs.eip);
uint32_t data = ptrace(PT_PEEK, g_pid, (void*)regs.eip, 0); uint32_t data = ptrace(PT_PEEK, g_pid, (void*)regs.eip, 0);
printf("data: 0x%x\n", data); printf("peeked data: 0x%x\n", data);
if (ptrace(PT_POKE, g_pid, (void*)regs.eip, data) < 0) {
perror("poke");
return 1;
}
if (ptrace(PT_CONTINUE, g_pid, 0, 0) == -1) { if (ptrace(PT_CONTINUE, g_pid, 0, 0) == -1) {
perror("continue"); perror("continue");

View file

@ -4916,8 +4916,11 @@ int Process::sys$ptrace(const Syscall::SC_ptrace_params* user_params)
if (params.pid == m_pid) if (params.pid == m_pid)
return -EINVAL; return -EINVAL;
InterruptDisabler disabler; Thread* peer = nullptr;
auto* peer = Thread::from_tid(params.pid); {
InterruptDisabler disabler;
peer = Thread::from_tid(params.pid);
}
if (!peer) if (!peer)
return -ESRCH; return -ESRCH;
@ -4974,6 +4977,7 @@ int Process::sys$ptrace(const Syscall::SC_ptrace_params* user_params)
} }
break; break;
} }
case PT_PEEK: { case PT_PEEK: {
uint32_t* addr = reinterpret_cast<uint32_t*>(params.addr); uint32_t* addr = reinterpret_cast<uint32_t*>(params.addr);
if (!MM.validate_user_read(peer->process(), VirtualAddress(addr), sizeof(uint32_t))) { 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; result = *addr;
return result; 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; break;
} }

View file

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

View file

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

View file

@ -37,6 +37,7 @@ __BEGIN_DECLS
#define PT_GETREGS 5 #define PT_GETREGS 5
#define PT_DETACH 6 #define PT_DETACH 6
#define PT_PEEK 7 #define PT_PEEK 7
#define PT_POKE 8
int ptrace(int request, pid_t pid, void* addr, int data); int ptrace(int request, pid_t pid, void* addr, int data);