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:
markj 2019-09-26 15:35:35 +00:00
parent edad331b44
commit e97c4bdc7f

View File

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