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/Process.cpp | |
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/Process.cpp')
-rw-r--r-- | Kernel/Process.cpp | 42 |
1 files changed, 40 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; } |