mirror of
https://github.com/RGBCube/serenity
synced 2025-05-23 18:45:07 +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
|
@ -122,6 +122,8 @@ VirtualAddress get_entry_point(int pid)
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
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)
|
if (argc == 1)
|
||||||
return usage();
|
return usage();
|
||||||
|
|
||||||
|
@ -157,7 +159,12 @@ int main(int argc, char** argv)
|
||||||
printf("eip:0x%x\n", regs.eip);
|
printf("eip:0x%x\n", regs.eip);
|
||||||
|
|
||||||
uint32_t data = ptrace(PT_PEEK, g_pid, (void*)regs.eip, 0);
|
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) {
|
if (ptrace(PT_CONTINUE, g_pid, 0, 0) == -1) {
|
||||||
perror("continue");
|
perror("continue");
|
||||||
|
|
|
@ -4916,8 +4916,11 @@ int Process::sys$ptrace(const Syscall::SC_ptrace_params* user_params)
|
||||||
if (params.pid == m_pid)
|
if (params.pid == m_pid)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
InterruptDisabler disabler;
|
Thread* peer = nullptr;
|
||||||
auto* peer = Thread::from_tid(params.pid);
|
{
|
||||||
|
InterruptDisabler disabler;
|
||||||
|
peer = Thread::from_tid(params.pid);
|
||||||
|
}
|
||||||
if (!peer)
|
if (!peer)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
|
@ -4974,6 +4977,7 @@ int Process::sys$ptrace(const Syscall::SC_ptrace_params* user_params)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PT_PEEK: {
|
case PT_PEEK: {
|
||||||
uint32_t* addr = reinterpret_cast<uint32_t*>(params.addr);
|
uint32_t* addr = reinterpret_cast<uint32_t*>(params.addr);
|
||||||
if (!MM.validate_user_read(peer->process(), VirtualAddress(addr), sizeof(uint32_t))) {
|
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;
|
result = *addr;
|
||||||
|
|
||||||
return result;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -555,3 +555,4 @@ struct rtentry {
|
||||||
#define PT_GETREGS 5
|
#define PT_GETREGS 5
|
||||||
#define PT_DETACH 6
|
#define PT_DETACH 6
|
||||||
#define PT_PEEK 7
|
#define PT_PEEK 7
|
||||||
|
#define PT_POKE 8
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <AK/Weakable.h>
|
#include <AK/Weakable.h>
|
||||||
#include <Kernel/Heap/SlabAllocator.h>
|
#include <Kernel/Heap/SlabAllocator.h>
|
||||||
#include <Kernel/VM/RangeAllocator.h>
|
#include <Kernel/VM/RangeAllocator.h>
|
||||||
|
#include <Kernel/VM/VMObject.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -79,6 +80,7 @@ public:
|
||||||
|
|
||||||
const VMObject& vmobject() const { return *m_vmobject; }
|
const VMObject& vmobject() const { return *m_vmobject; }
|
||||||
VMObject& vmobject() { return *m_vmobject; }
|
VMObject& vmobject() { return *m_vmobject; }
|
||||||
|
void set_vmobject(NonnullRefPtr<VMObject>&& obj) { m_vmobject = obj; }
|
||||||
|
|
||||||
bool is_shared() const { return m_shared; }
|
bool is_shared() const { return m_shared; }
|
||||||
void set_shared(bool shared) { m_shared = shared; }
|
void set_shared(bool shared) { m_shared = shared; }
|
||||||
|
|
|
@ -37,6 +37,7 @@ __BEGIN_DECLS
|
||||||
#define PT_GETREGS 5
|
#define PT_GETREGS 5
|
||||||
#define PT_DETACH 6
|
#define PT_DETACH 6
|
||||||
#define PT_PEEK 7
|
#define PT_PEEK 7
|
||||||
|
#define PT_POKE 8
|
||||||
|
|
||||||
int ptrace(int request, pid_t pid, void* addr, int data);
|
int ptrace(int request, pid_t pid, void* addr, int data);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue