Date: Wed, 20 Mar 2019 13:07:57 +0000 (UTC) From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r345324 - head/sys/vm Message-ID: <201903201307.x2KD7vHR079659@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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.
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903201307.x2KD7vHR079659>