⬢ DragonFlyBSD Kernel Audit
DF-5289 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index e8b0bb5..f66966a 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -2676,9 +2676,27 @@ vm_fault_unwire(vm_map_t map, vm_map_entry_t entry)
 	pmap = vm_map_pmap(map);
 	start = entry->ba.start;
 	end = entry->ba.end;
-	fictitious = entry->ba.object &&
+	/*
+	 * Mirror vm_fault_wire()'s classification (see ~line 2607):
+	 * VM_MAPTYPE_UKSMAP entries have no VM object and are backed
+	 * by a transient fictitious vm_page fabricated in vm_fault();
+	 * the pmap wiring takes no vm_page wire on the underlying
+	 * real page, so the unwire path must not touch one either.
+	 */
+	switch (entry->maptype) {
+	case VM_MAPTYPE_NORMAL:
+	case VM_MAPTYPE_VPAGETABLE:
+		fictitious = entry->ba.object &&
 			((entry->ba.object->type == OBJT_DEVICE) ||
 			 (entry->ba.object->type == OBJT_MGTDEVICE));
+		break;
+	case VM_MAPTYPE_UKSMAP:
+		fictitious = TRUE;
+		break;
+	default:
+		fictitious = FALSE;
+		break;
+	}
 	if (entry->eflags & MAP_ENTRY_KSTACK)
 		start += PAGE_SIZE;
 
diff --git a/sys/platform/vkernel64/platform/pmap.c b/sys/platform/vkernel64/platform/pmap.c
index 35f17b9..d404d5a 100644
--- a/sys/platform/vkernel64/platform/pmap.c
+++ b/sys/platform/vkernel64/platform/pmap.c
@@ -2652,8 +2652,19 @@ pmap_unwire(pmap_t pmap, vm_offset_t *pva)
 	if (pmap_pte_w(pte)) {
 		atomic_add_long(&pmap->pm_stats.wired_count, -1);
 		atomic_clear_long(pte, VPTE_WIRED);
-		pa = *pte & VPTE_FRAME;
-		m = PHYS_TO_VM_PAGE(pa);	/* held by wired count */
+
+		/*
+		 * Only managed pages carry a wire count taken by
+		 * pmap_enter().  Unmanaged (fictitious / UKSMAP) wired
+		 * ptes must not yield a vm_page to the caller - the
+		 * underlying page was never wired via the pmap.
+		 */
+		if (*pte & VPTE_MANAGED) {
+			pa = *pte & VPTE_FRAME;
+			m = PHYS_TO_VM_PAGE(pa);/* held by wired count */
+		} else {
+			m = NULL;
+		}
 		/* caller handles m->wire_count */
 	} else {
 		m = NULL;