Correct an error in pmap_promote_pde() that may result in an errant
promotion within the kernel's address space. Specifically, pmap_promote_pde() is only called when the page table page (PTP) that is referenced by the given PDE has a full "use count", i.e., its wire_count is 512. Although this guarantees for a user address space that all 512 PTEs in the PTP hold valid mappings, the same is not true of the kernel's address space. A kernel PTP always has a use count of 512 regardless of the state of the PTEs. Therefore, pmap_promote_pde() should not assume (or assert) that the first PTE in the PTP is valid.
This commit is contained in:
parent
4ca07625aa
commit
71e26e2c0e
@ -2775,22 +2775,20 @@ pmap_promote_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
|
||||
|
||||
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
|
||||
firstpte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME);
|
||||
KASSERT((*firstpte & PG_V) != 0,
|
||||
("pmap_promote_pde: firstpte is missing PG_V"));
|
||||
if ((*firstpte & PG_A) == 0) {
|
||||
newpde = *firstpte;
|
||||
if ((newpde & (PG_A | PG_V)) != (PG_A | PG_V)) {
|
||||
pmap_pde_p_failures++;
|
||||
CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx"
|
||||
" in pmap %p", va, pmap);
|
||||
return;
|
||||
}
|
||||
pa = *firstpte & PG_PS_FRAME;
|
||||
newpde = *firstpte;
|
||||
if ((newpde & (PG_M | PG_RW)) == PG_RW)
|
||||
newpde &= ~PG_RW;
|
||||
|
||||
/*
|
||||
* Check all the ptes before promotion
|
||||
*/
|
||||
pa = newpde & PG_PS_FRAME;
|
||||
for (pte = firstpte; pte < firstpte + NPTEPG; pte++) {
|
||||
retry:
|
||||
oldpte = *pte;
|
||||
|
Loading…
x
Reference in New Issue
Block a user