diff options
author | Itamar <itamar8910@gmail.com> | 2020-04-05 22:58:44 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-13 00:53:22 +0200 |
commit | b306ac9b2be2692192a5dba9ea974a5cb41e7df4 (patch) | |
tree | 6308b8754cf3e28f84437d48e0bdf07cc3c5368e /Kernel | |
parent | 924fda19b0616a28e49ab28e99c4dea8a11bc758 (diff) | |
download | serenity-b306ac9b2be2692192a5dba9ea974a5cb41e7df4.zip |
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.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Process.cpp | 42 | ||||
-rw-r--r-- | Kernel/UnixTypes.h | 1 | ||||
-rw-r--r-- | Kernel/VM/Region.h | 2 |
3 files changed, 43 insertions, 2 deletions
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<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; } 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 <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; } |