DragonFlyBSD Kernel Audit
DF-2983 / fix.diff
← back to finding ↓ download raw
--- a/sys/vm/phys_pager.c
+++ b/sys/vm/phys_pager.c
@@ -110,8 +110,17 @@
 phys_pager_putpages(vm_object_t object, vm_page_t *m, int count,
 		    int flags, int *rtvals)
 {
+	int i;
 
-	panic("phys_pager_putpage called");
+	/*
+	 * OBJT_PHYS objects have no backing store.  Pages should always
+	 * be PG_UNQUEUED (phys_pager_getpage() and vm_fault set the
+	 * flag), but if a queue-managed page ever reaches us anyway,
+	 * report failure instead of panicking: the page stays dirty and
+	 * resident, preserving its contents.
+	 */
+	for (i = 0; i < count; ++i)
+		rtvals[i] = VM_PAGER_FAIL;
 }
 
 /*
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -2323,7 +2323,16 @@
 
 			/*
 			 * Zero the page and mark it valid.
+			 *
+			 * OBJT_PHYS pages are unmanaged: phys_pager_getpage()
+			 * sets PG_UNQUEUED.  Wiring faults (VM_FAULT_WIRE_MASK)
+			 * bypass the pager (TRYPAGER is false), so mirror the
+			 * pager here or unwiring leaves a queue-managed page in
+			 * a phys object, which the pagedaemon would later try
+			 * to launder -> phys_pager_putpages() panic.
 			 */
+			if (fs->mary[0]->object->type == OBJT_PHYS)
+				vm_page_flag_set(fs->mary[0], PG_UNQUEUED);
 			vm_page_zero_fill(fs->mary[0]);
 			mycpu->gd_cnt.v_zfod++;
 			fs->mary[0]->valid = VM_PAGE_BITS_ALL;