svn commit: r345324 - head/sys/vm
Konstantin Belousov
kib at FreeBSD.org
Wed Mar 20 13:07:58 UTC 2019
Author: kib
Date: Wed Mar 20 13:07:57 2019
New Revision: 345324
URL: https://svnweb.freebsd.org/changeset/base/345324
Log:
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 at 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
Modified:
head/sys/vm/vm_fault.c
Modified: head/sys/vm/vm_fault.c
==============================================================================
--- head/sys/vm/vm_fault.c Wed Mar 20 10:36:58 2019 (r345323)
+++ head/sys/vm/vm_fault.c Wed Mar 20 13:07:57 2019 (r345324)
@@ -1757,8 +1757,7 @@ again:
}
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 @@ again:
*/
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 @@ again:
* 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.
More information about the svn-src-head
mailing list