Fix handling of invalid pages in exec_map_first_page().

exec_map_first_page() would unconditionally free an unbacked, invalid
page from the executable image.  However, it is possible that the page
is wired, in which case it is incorrect to free the page, so check for
additional wirings first.

Reported by:	syzkaller
Tested by:	pho
Reviewed by:	kib
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D21767
This commit is contained in:
Mark Johnston 2019-09-26 15:35:35 +00:00
parent 9afb12bab4
commit 55248d32f2

View File

@ -981,8 +981,10 @@ exec_map_first_page(struct image_params *imgp)
if (ma[0]->valid != VM_PAGE_BITS_ALL) {
vm_page_xbusy(ma[0]);
if (!vm_pager_has_page(object, 0, NULL, &after)) {
vm_page_unwire_noq(ma[0]);
vm_page_free(ma[0]);
if (vm_page_unwire_noq(ma[0]))
vm_page_free(ma[0]);
else
vm_page_xunbusy(ma[0]);
VM_OBJECT_WUNLOCK(object);
return (EIO);
}
@ -1006,9 +1008,16 @@ exec_map_first_page(struct image_params *imgp)
initial_pagein = i;
rv = vm_pager_get_pages(object, ma, initial_pagein, NULL, NULL);
if (rv != VM_PAGER_OK) {
vm_page_unwire_noq(ma[0]);
for (i = 0; i < initial_pagein; i++)
vm_page_free(ma[i]);
if (vm_page_unwire_noq(ma[0]))
vm_page_free(ma[0]);
else
vm_page_xunbusy(ma[0]);
for (i = 1; i < initial_pagein; i++) {
if (!vm_page_wired(ma[i]))
vm_page_free(ma[i]);
else
vm_page_xunbusy(ma[i]);
}
VM_OBJECT_WUNLOCK(object);
return (EIO);
}