summaryrefslogtreecommitdiff
path: root/Kernel/Process.cpp
diff options
context:
space:
mode:
authorItamar <itamar8910@gmail.com>2020-04-05 22:58:44 +0300
committerAndreas Kling <kling@serenityos.org>2020-04-13 00:53:22 +0200
commitb306ac9b2be2692192a5dba9ea974a5cb41e7df4 (patch)
tree6308b8754cf3e28f84437d48e0bdf07cc3c5368e /Kernel/Process.cpp
parent924fda19b0616a28e49ab28e99c4dea8a11bc758 (diff)
downloadserenity-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.cpp42
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;
}