ptrace: POKEDATA, permission fixes for PEEKDATA

This commit is contained in:
K. Lange 2021-09-24 12:00:46 +09:00
parent 5825bf0c9e
commit c8a37456ec
4 changed files with 86 additions and 5 deletions

View File

@ -403,6 +403,23 @@ static void show_commandline(pid_t pid, int status, struct regs * regs) {
if (signum == SIGINT) signum = 0;
ptrace(PTRACE_CONT, pid, NULL, (void*)(uintptr_t)signum);
return;
} else if (!strcmp(buf, "poke")) {
char * addr = arg;
char * data = strstr(addr, " ");
if (!data) {
fprintf(stderr, "usage: poke addr byte\n");
continue;
}
*data = '\0'; data++;
uintptr_t addr_ = strtoul(addr, NULL, 0);
uintptr_t data_ = strtoul(data, NULL, 0);
if (ptrace(PTRACE_POKEDATA, pid, (void*)addr_, (void*)&data_) != 0) {
fprintf(stderr, "poke: %s\n", strerror(errno));
continue;
}
} else if (!strcmp(buf, "print") || !strcmp(buf,"p")) {
char * fmt = arg;
char * sp = strstr(arg, " ");

View File

@ -12,7 +12,8 @@ enum __ptrace_request {
PTRACE_TRACEME,
PTRACE_GETREGS,
PTRACE_PEEKDATA,
PTRACE_SIGNALS_ONLY_PLZ
PTRACE_SIGNALS_ONLY_PLZ,
PTRACE_POKEDATA
};
enum __ptrace_event {

View File

@ -194,6 +194,43 @@ void * mmu_map_from_physical(uintptr_t frameaddress) {
return (void*)(frameaddress | HIGH_MAP_REGION);
}
union PML * mmu_get_page_other(union PML * root, uintptr_t virtAddr) {
uintptr_t realBits = virtAddr & CANONICAL_MASK;
uintptr_t pageAddr = realBits >> PAGE_SHIFT;
unsigned int pml4_entry = (pageAddr >> 27) & ENTRY_MASK;
unsigned int pdp_entry = (pageAddr >> 18) & ENTRY_MASK;
unsigned int pd_entry = (pageAddr >> 9) & ENTRY_MASK;
unsigned int pt_entry = (pageAddr) & ENTRY_MASK;
/* Get the PML4 entry for this address */
if (!root[pml4_entry].bits.present) {
return NULL;
}
union PML * pdp = mmu_map_from_physical((uintptr_t)root[pml4_entry].bits.page << PAGE_SHIFT);
if (!pdp[pdp_entry].bits.present) {
return NULL;
}
if (pdp[pdp_entry].bits.size) {
return NULL;
}
union PML * pd = mmu_map_from_physical((uintptr_t)pdp[pdp_entry].bits.page << PAGE_SHIFT);
if (!pd[pd_entry].bits.present) {
return NULL;
}
if (pd[pd_entry].bits.size) {
return NULL;
}
union PML * pt = mmu_map_from_physical((uintptr_t)pd[pd_entry].bits.page << PAGE_SHIFT);
return (union PML *)&pt[pt_entry];
}
/**
* @brief Find the physical address at a given virtual address.
*

View File

@ -75,14 +75,17 @@ long ptrace_getregs(pid_t pid, void * data) {
return 0;
}
extern union PML * mmu_get_page_other(union PML * root, uintptr_t virtAddr);
long ptrace_peek(pid_t pid, void * addr, void * data) {
if (!data || ptr_validate(data, "ptrace")) return -EFAULT;
process_t * tracee = process_from_pid(pid);
if (!tracee || (tracee->tracer != this_core->current_process->id) || !(tracee->flags & PROC_FLAG_SUSPENDED)) return -ESRCH;
/* Figure out where *addr is...
* TODO: We don't ever really page things to disk, and we don't have file
* mappings that may be not-present, so this is fairly straightforward for now... */
union PML * page_entry = mmu_get_page_other(tracee->thread.page_directory->directory, (uintptr_t)addr);
if (!page_entry) return -EFAULT;
if (!page_entry->bits.present || !page_entry->bits.user) return -EFAULT;
uintptr_t mapped_address = mmu_map_to_physical(tracee->thread.page_directory->directory, (uintptr_t)addr);
if ((intptr_t)mapped_address < 0 && (intptr_t)mapped_address > -10) return -EFAULT;
@ -95,6 +98,28 @@ long ptrace_peek(pid_t pid, void * addr, void * data) {
return 0;
}
long ptrace_poke(pid_t pid, void * addr, void * data) {
if (!data || ptr_validate(data, "ptrace")) return -EFAULT;
process_t * tracee = process_from_pid(pid);
if (!tracee || (tracee->tracer != this_core->current_process->id) || !(tracee->flags & PROC_FLAG_SUSPENDED)) return -ESRCH;
union PML * page_entry = mmu_get_page_other(tracee->thread.page_directory->directory, (uintptr_t)addr);
if (!page_entry) return -EFAULT;
if (!page_entry->bits.present || !page_entry->bits.user || !page_entry->bits.writable) return -EFAULT;
uintptr_t mapped_address = mmu_map_to_physical(tracee->thread.page_directory->directory, (uintptr_t)addr);
if ((intptr_t)mapped_address < 0 && (intptr_t)mapped_address > -10) return -EFAULT;
uintptr_t blarg = (uintptr_t)mmu_map_from_physical(mapped_address);
/* Yeah, uh, one byte. That works. */
*(char*)blarg = *(char*)data;
return 0;
}
long ptrace_signals_only(pid_t pid) {
process_t * tracee = process_from_pid(pid);
if (!tracee || (tracee->tracer != this_core->current_process->id) || !(tracee->flags & PROC_FLAG_SUSPENDED)) return -ESRCH;
@ -102,7 +127,6 @@ long ptrace_signals_only(pid_t pid) {
return 0;
}
long ptrace_handle(long request, pid_t pid, void * addr, void * data) {
switch (request) {
case PTRACE_ATTACH:
@ -115,6 +139,8 @@ long ptrace_handle(long request, pid_t pid, void * addr, void * data) {
return ptrace_continue(pid,(uintptr_t)data);
case PTRACE_PEEKDATA:
return ptrace_peek(pid,addr,data);
case PTRACE_POKEDATA:
return ptrace_poke(pid,addr,data);
case PTRACE_SIGNALS_ONLY_PLZ:
return ptrace_signals_only(pid);
default: