Further limit when we call pmap_fault.

We should only call pmap_fault in the kernel when accessing a userspace
address. As this should always happen through specific functions that set
a fault handler we can use this to limit calls to pmap_fault to when this
is set.

This should help with NULL pointer dereferences when we are unable to sleep
so we fall into the correct case.

Sponsored by:	DARPA, AFRL
This commit is contained in:
Andrew Turner 2018-05-30 15:25:48 +00:00
parent b98d2b35df
commit e2b8bf0a18

View File

@ -190,16 +190,32 @@ data_abort(struct thread *td, struct trapframe *frame, uint64_t esr,
}
/*
* We may fault from userspace or when in a DMAP region due to
* a superpage being unmapped when the access took place. In these
* cases we need to wait for the pmap to be unlocked and check
* if the translation is still invalid.
* The call to pmap_fault can be dangerous when coming from the
* kernel as it may be not be able to lock the pmap to check if
* the address is now valid. Because of this we filter the cases
* when we are not going to see superpage activity.
*/
if (map != kernel_map || VIRT_IN_DMAP(far)) {
if (pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
return;
if (!lower) {
/*
* We may fault in a DMAP region due to a superpage being
* unmapped when the access took place.
*/
if (map == kernel_map && !VIRT_IN_DMAP(far))
goto no_pmap_fault;
/*
* We can also fault in the userspace handling functions,
* e.g. copyin. In these cases we will have set a fault
* handler so we can check if this is set before calling
* pmap_fault.
*/
if (map != kernel_map && pcb->pcb_onfault == 0)
goto no_pmap_fault;
}
if (pmap_fault(map->pmap, esr, far) == KERN_SUCCESS)
return;
no_pmap_fault:
KASSERT(td->td_md.md_spinlock_count == 0,
("data abort with spinlock held"));
if (td->td_critnest != 0 || WITNESS_CHECK(WARN_SLEEPOK |