pmap: Fix largemap restart checks in the kernel_maps sysctl handler

The purpose of these checks is to ensure that the address of the
next-level page table page is valid, since nothing is synchronizing with
a concurrent update of the large map and large map PTPs are freed to the
system.  However, if PG_PS is set, there is no next level.

Reported by:	rpokala
Reviewed by:	kib
Tested by:	rpokala
MFC after:	3 days
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D28922
This commit is contained in:
Mark Johnston 2021-02-25 18:49:47 -05:00
parent 90972f0402
commit aac25e2225

View File

@ -11348,9 +11348,6 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
continue;
}
pa = pdpe & PG_FRAME;
if (PMAP_ADDRESS_IN_LARGEMAP(sva) &&
vm_phys_paddr_to_vm_page(pa) == NULL)
goto restart;
if ((pdpe & PG_PS) != 0) {
sva = rounddown2(sva, NBPDP);
sysctl_kmaps_check(sb, &range, sva, pml4e, pdpe,
@ -11359,6 +11356,15 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
sva += NBPDP;
continue;
}
if (PMAP_ADDRESS_IN_LARGEMAP(sva) &&
vm_phys_paddr_to_vm_page(pa) == NULL) {
/*
* Page table pages for the large map may be
* freed. Validate the next-level address
* before descending.
*/
goto restart;
}
pd = (pd_entry_t *)PHYS_TO_DMAP(pa);
for (k = pmap_pde_index(sva); k < NPDEPG; k++) {
@ -11370,9 +11376,6 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
continue;
}
pa = pde & PG_FRAME;
if (PMAP_ADDRESS_IN_LARGEMAP(sva) &&
vm_phys_paddr_to_vm_page(pa) == NULL)
goto restart;
if ((pde & PG_PS) != 0) {
sva = rounddown2(sva, NBPDR);
sysctl_kmaps_check(sb, &range, sva,
@ -11381,6 +11384,15 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
sva += NBPDR;
continue;
}
if (PMAP_ADDRESS_IN_LARGEMAP(sva) &&
vm_phys_paddr_to_vm_page(pa) == NULL) {
/*
* Page table pages for the large map
* may be freed. Validate the
* next-level address before descending.
*/
goto restart;
}
pt = (pt_entry_t *)PHYS_TO_DMAP(pa);
for (l = pmap_pte_index(sva); l < NPTEPG; l++,