vm_fault_copy_entry: accept invalid source pages.
Either msync(MS_INVALIDATE) or the object unlock during vnode truncation can expose invalid pages backing wired entries. Accept them, but do not install them into destrination pmap. We must create copied pages in the copy case, because e.g. vm_object_unwire() expects that the entry is fully backed. Reported by: syzkaller, via emaste Reported by: syzbot+514d40ce757a3f8b15bc@syzkaller.appspotmail.com Reviewed by: markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D19615
This commit is contained in:
parent
5e874d26a2
commit
45d72c7d7f
@ -1757,8 +1757,7 @@ vm_fault_copy_entry(vm_map_t dst_map, vm_map_t src_map,
|
||||
}
|
||||
pmap_copy_page(src_m, dst_m);
|
||||
VM_OBJECT_RUNLOCK(object);
|
||||
dst_m->valid = VM_PAGE_BITS_ALL;
|
||||
dst_m->dirty = VM_PAGE_BITS_ALL;
|
||||
dst_m->dirty = dst_m->valid = src_m->valid;
|
||||
} else {
|
||||
dst_m = src_m;
|
||||
if (vm_page_sleep_if_busy(dst_m, "fltupg"))
|
||||
@ -1771,8 +1770,6 @@ vm_fault_copy_entry(vm_map_t dst_map, vm_map_t src_map,
|
||||
*/
|
||||
break;
|
||||
vm_page_xbusy(dst_m);
|
||||
KASSERT(dst_m->valid == VM_PAGE_BITS_ALL,
|
||||
("invalid dst page %p", dst_m));
|
||||
}
|
||||
VM_OBJECT_WUNLOCK(dst_object);
|
||||
|
||||
@ -1780,9 +1777,18 @@ vm_fault_copy_entry(vm_map_t dst_map, vm_map_t src_map,
|
||||
* Enter it in the pmap. If a wired, copy-on-write
|
||||
* mapping is being replaced by a write-enabled
|
||||
* mapping, then wire that new mapping.
|
||||
*
|
||||
* The page can be invalid if the user called
|
||||
* msync(MS_INVALIDATE) or truncated the backing vnode
|
||||
* or shared memory object. In this case, do not
|
||||
* insert it into pmap, but still do the copy so that
|
||||
* all copies of the wired map entry have similar
|
||||
* backing pages.
|
||||
*/
|
||||
pmap_enter(dst_map->pmap, vaddr, dst_m, prot,
|
||||
access | (upgrade ? PMAP_ENTER_WIRED : 0), 0);
|
||||
if (dst_m->valid == VM_PAGE_BITS_ALL) {
|
||||
pmap_enter(dst_map->pmap, vaddr, dst_m, prot,
|
||||
access | (upgrade ? PMAP_ENTER_WIRED : 0), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark it no longer busy, and put it on the active list.
|
||||
|
Loading…
Reference in New Issue
Block a user