Correct a rare use-after-free error in pmap_copy(). This error was

introduced in amd64 revision 1.540 and i386 revision 1.547.  However, it
had no harmful effects until after a recent change, r189698, on amd64.
(In other words, the error is harmless in RELENG_7.)

The error is triggered by the failure to allocate a pv entry for the one
and only mapping in a page table page.  I am addressing the error by
changing pmap_copy() to abort if either pv entry allocation or page
table page allocation fails.  This is appropriate because the creation of
mappings by pmap_copy() is optional.  They are a (possible) optimization,
and not a requirement.

Correct a nearby whitespace error in the i386 pmap_copy().

Crash reported by: jeff@
MFC after:	6 weeks
This commit is contained in:
alc 2009-05-13 07:42:53 +00:00
parent 82da6bfdea
commit 2553ba9c64
2 changed files with 7 additions and 3 deletions

View File

@ -3556,7 +3556,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
dstmpte->wire_count++;
else if ((dstmpte = pmap_allocpte(dst_pmap,
addr, M_NOWAIT)) == NULL)
break;
goto out;
dst_pte = (pt_entry_t *)
PHYS_TO_DMAP(VM_PAGE_TO_PHYS(dstmpte));
dst_pte = &dst_pte[pmap_pte_index(addr)];
@ -3579,6 +3579,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
addr);
pmap_free_zero_pages(free);
}
goto out;
}
if (dstmpte->wire_count >= srcmpte->wire_count)
break;
@ -3587,6 +3588,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
src_pte++;
}
}
out:
vm_page_unlock_queues();
PMAP_UNLOCK(src_pmap);
PMAP_UNLOCK(dst_pmap);

View File

@ -3638,7 +3638,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
dstmpte = pmap_allocpte(dst_pmap, addr,
M_NOWAIT);
if (dstmpte == NULL)
break;
goto out;
dst_pte = pmap_pte_quick(dst_pmap, addr);
if (*dst_pte == 0 &&
pmap_try_insert_pv_entry(dst_pmap, addr,
@ -3653,12 +3653,13 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
dst_pmap->pm_stats.resident_count++;
} else {
free = NULL;
if (pmap_unwire_pte_hold( dst_pmap,
if (pmap_unwire_pte_hold(dst_pmap,
dstmpte, &free)) {
pmap_invalidate_page(dst_pmap,
addr);
pmap_free_zero_pages(free);
}
goto out;
}
if (dstmpte->wire_count >= srcmpte->wire_count)
break;
@ -3667,6 +3668,7 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
src_pte++;
}
}
out:
sched_unpin();
vm_page_unlock_queues();
PMAP_UNLOCK(src_pmap);