diff options
author | alc <alc@FreeBSD.org> | 2009-05-13 07:42:53 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2009-05-13 07:42:53 +0000 |
commit | 2553ba9c6495ed3b8b92f21dc3c0eaee5e7fc188 (patch) | |
tree | cbac0558bc7205f8fe1f2e648d1126cbc3070955 /sys/i386 | |
parent | 82da6bfdea2a3b999744f0b05506fe0e3a185061 (diff) | |
download | FreeBSD-src-2553ba9c6495ed3b8b92f21dc3c0eaee5e7fc188.zip FreeBSD-src-2553ba9c6495ed3b8b92f21dc3c0eaee5e7fc188.tar.gz |
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
Diffstat (limited to 'sys/i386')
-rw-r--r-- | sys/i386/i386/pmap.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 7f6900d..5f016d5 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -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); |