mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 08:32:43 +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) | ||||
| { | ||||
|     // TODO: pledge & unveil
 | ||||
|     // TOOD: check that we didn't somehow hurt performance. boot seems slower? (or it's just laptop battey)
 | ||||
|     if (argc == 1) | ||||
|         return usage(); | ||||
| 
 | ||||
|  | @ -157,7 +159,12 @@ int main(int argc, char** argv) | |||
|     printf("eip:0x%x\n", regs.eip); | ||||
| 
 | ||||
|     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) { | ||||
|         perror("continue"); | ||||
|  |  | |||
|  | @ -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; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -555,3 +555,4 @@ struct rtentry { | |||
| #define PT_GETREGS 5 | ||||
| #define PT_DETACH 6 | ||||
| #define PT_PEEK 7 | ||||
| #define PT_POKE 8 | ||||
|  |  | |||
|  | @ -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; } | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ __BEGIN_DECLS | |||
| #define PT_GETREGS 5 | ||||
| #define PT_DETACH 6 | ||||
| #define PT_PEEK 7 | ||||
| #define PT_POKE 8 | ||||
| 
 | ||||
| int ptrace(int request, pid_t pid, void* addr, int data); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Itamar
						Itamar