mirror of
https://github.com/RGBCube/serenity
synced 2025-05-16 17:55:06 +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:
parent
924fda19b0
commit
b306ac9b2b
5 changed files with 52 additions and 3 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue