diff --git a/Applications/Debugger/main.cpp b/Applications/Debugger/main.cpp index 9d9b341ba5..59d78719b0 100644 --- a/Applications/Debugger/main.cpp +++ b/Applications/Debugger/main.cpp @@ -122,6 +122,8 @@ VirtualAddress get_entry_point(int pid) 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) return usage(); @@ -157,7 +159,12 @@ int main(int argc, char** argv) printf("eip:0x%x\n", regs.eip); 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) { perror("continue"); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index d3ccd13b87..ee27b6a7ba 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -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(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(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(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; } diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index 4448de7f00..e698a1b3f2 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -555,3 +555,4 @@ struct rtentry { #define PT_GETREGS 5 #define PT_DETACH 6 #define PT_PEEK 7 +#define PT_POKE 8 diff --git a/Kernel/VM/Region.h b/Kernel/VM/Region.h index 5671dec795..b71c8986e9 100644 --- a/Kernel/VM/Region.h +++ b/Kernel/VM/Region.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace Kernel { @@ -79,6 +80,7 @@ public: const VMObject& vmobject() const { return *m_vmobject; } VMObject& vmobject() { return *m_vmobject; } + void set_vmobject(NonnullRefPtr&& obj) { m_vmobject = obj; } bool is_shared() const { return m_shared; } void set_shared(bool shared) { m_shared = shared; } diff --git a/Libraries/LibC/sys/ptrace.h b/Libraries/LibC/sys/ptrace.h index 11559bcc9f..8182188e7f 100644 --- a/Libraries/LibC/sys/ptrace.h +++ b/Libraries/LibC/sys/ptrace.h @@ -37,6 +37,7 @@ __BEGIN_DECLS #define PT_GETREGS 5 #define PT_DETACH 6 #define PT_PEEK 7 +#define PT_POKE 8 int ptrace(int request, pid_t pid, void* addr, int data);