page fault handler: protect thread accesses

current cpu's thread can be NULL during init, we don't want null derefs
in the page fault handler

Change-Id: I0a2c22b39cae2c258d211317cffc2408e19f3bbf
This commit is contained in:
Dominique Martinet
2019-02-06 11:38:39 +09:00
committed by Masamichi Takagi
parent fe08ac4a67
commit f5023c9730
3 changed files with 25 additions and 11 deletions

View File

@ -1563,7 +1563,7 @@ void
unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs) unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs)
{ {
const uintptr_t address = (uintptr_t)fault_addr; const uintptr_t address = (uintptr_t)fault_addr;
struct process_vm *vm = thread->vm; struct process_vm *vm;
struct vm_range *range; struct vm_range *range;
unsigned long irqflags; unsigned long irqflags;
unsigned long error = 0; unsigned long error = 0;
@ -1578,6 +1578,11 @@ unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs)
(error & PF_RSVD ? "was" : "wasn't"), (error & PF_RSVD ? "was" : "wasn't"),
(error & PF_INSTR ? "was" : "wasn't")); (error & PF_INSTR ? "was" : "wasn't"));
if (!thread)
goto skipvm;
vm = thread->vm;
range = lookup_process_memory_range(vm, address, address+1); range = lookup_process_memory_range(vm, address, address+1);
if (range) { if (range) {
__kprintf("address is in range, flag: 0x%lx\n", __kprintf("address is in range, flag: 0x%lx\n",
@ -1587,6 +1592,7 @@ unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs)
__kprintf("address is out of range! \n"); __kprintf("address is out of range! \n");
} }
skipvm:
kprintf_unlock(irqflags); kprintf_unlock(irqflags);
/* TODO */ /* TODO */

View File

@ -1089,7 +1089,7 @@ void
unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs) unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs)
{ {
const uintptr_t address = (uintptr_t)fault_addr; const uintptr_t address = (uintptr_t)fault_addr;
struct process_vm *vm = thread->vm; struct process_vm *vm;
struct vm_range *range; struct vm_range *range;
unsigned long irqflags; unsigned long irqflags;
unsigned long error = ((struct x86_user_context *)regs)->gpr.error; unsigned long error = ((struct x86_user_context *)regs)->gpr.error;
@ -1104,6 +1104,11 @@ unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs)
(error & PF_RSVD ? "was" : "wasn't"), (error & PF_RSVD ? "was" : "wasn't"),
(error & PF_INSTR ? "was" : "wasn't")); (error & PF_INSTR ? "was" : "wasn't"));
if (!thread)
goto skipvm;
vm = thread->vm;
range = lookup_process_memory_range(vm, address, address+1); range = lookup_process_memory_range(vm, address, address+1);
if (range) { if (range) {
__kprintf("address is in range, flag: 0x%lx\n", __kprintf("address is in range, flag: 0x%lx\n",
@ -1113,6 +1118,7 @@ unhandled_page_fault(struct thread *thread, void *fault_addr, void *regs)
__kprintf("address is out of range! \n"); __kprintf("address is out of range! \n");
} }
skipvm:
kprintf_unlock(irqflags); kprintf_unlock(irqflags);
/* TODO */ /* TODO */

View File

@ -1150,7 +1150,7 @@ static void page_fault_handler(void *fault_addr, uint64_t reason, void *regs)
int error; int error;
#ifdef PROFILE_ENABLE #ifdef PROFILE_ENABLE
uint64_t t_s = 0; uint64_t t_s = 0;
if (thread->profile) if (thread && thread->profile)
t_s = rdtsc(); t_s = rdtsc();
#endif // PROFILE_ENABLE #endif // PROFILE_ENABLE
@ -1163,7 +1163,7 @@ static void page_fault_handler(void *fault_addr, uint64_t reason, void *regs)
cpu_enable_interrupt(); cpu_enable_interrupt();
if ((uintptr_t)fault_addr < PAGE_SIZE) { if ((uintptr_t)fault_addr < PAGE_SIZE || !thread) {
error = -EINVAL; error = -EINVAL;
} else { } else {
error = page_fault_process_vm(thread->vm, fault_addr, reason); error = page_fault_process_vm(thread->vm, fault_addr, reason);
@ -1179,9 +1179,9 @@ static void page_fault_handler(void *fault_addr, uint64_t reason, void *regs)
// no return // no return
} }
kprintf("%s fault VM failed for TID: %d, addr: 0x%lx, " kprintf("%s fault VM failed for TID: %d, addr: 0x%lx, reason: %d, error: %d\n",
"reason: %d, error: %d\n", __FUNCTION__, __func__, thread ? thread->tid : -1, fault_addr,
thread->tid, fault_addr, reason, error); reason, error);
unhandled_page_fault(thread, fault_addr, regs); unhandled_page_fault(thread, fault_addr, regs);
preempt_enable(); preempt_enable();
memset(&info, '\0', sizeof info); memset(&info, '\0', sizeof info);
@ -1192,12 +1192,14 @@ static void page_fault_handler(void *fault_addr, uint64_t reason, void *regs)
set_signal(SIGBUS, regs, &info); set_signal(SIGBUS, regs, &info);
} }
else { else {
struct process_vm *vm = thread->vm; struct vm_range *range = NULL;
struct vm_range *range;
info.si_signo = SIGSEGV; info.si_signo = SIGSEGV;
info.si_code = SEGV_MAPERR; info.si_code = SEGV_MAPERR;
range = lookup_process_memory_range(vm, (uintptr_t)fault_addr, ((uintptr_t)fault_addr) + 1); if (thread)
range = lookup_process_memory_range(thread->vm,
(uintptr_t)fault_addr,
((uintptr_t)fault_addr) + 1);
if (range) if (range)
info.si_code = SEGV_ACCERR; info.si_code = SEGV_ACCERR;
info._sifields._sigfault.si_addr = fault_addr; info._sifields._sigfault.si_addr = fault_addr;
@ -1219,7 +1221,7 @@ out:
set_cputime(interrupt_from_user(regs) ? set_cputime(interrupt_from_user(regs) ?
CPUTIME_MODE_K2U : CPUTIME_MODE_K2K_OUT); CPUTIME_MODE_K2U : CPUTIME_MODE_K2K_OUT);
#ifdef PROFILE_ENABLE #ifdef PROFILE_ENABLE
if (thread->profile) if (thread && thread->profile)
profile_event_add(PROFILE_page_fault, (rdtsc() - t_s)); profile_event_add(PROFILE_page_fault, (rdtsc() - t_s));
#endif // PROFILE_ENABLE #endif // PROFILE_ENABLE
return; return;