mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 09:02: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) | 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; | ||||||
| 
 | 
 | ||||||
|  |     Thread* peer = nullptr; | ||||||
|  |     { | ||||||
|         InterruptDisabler disabler; |         InterruptDisabler disabler; | ||||||
|     auto* peer = Thread::from_tid(params.pid); |         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
	
	 Itamar
						Itamar