⬢ DragonFlyBSD Kernel Audit
DF-5450 / fix.diff
← back to finding ↓ download raw
--- a/sys/platform/pc64/x86_64/nexus.c
+++ b/sys/platform/pc64/x86_64/nexus.c
@@ -426,6 +426,17 @@
 	 */
 	if (rman_get_bustag(r) == X86_64_BUS_SPACE_MEM) {
 		caddr_t vaddr = 0;
+		int error;
+
+		/*
+		 * The mapping step must happen exactly once.  pmap_mapdev()
+		 * is not idempotent while rman_activate_resource() is:
+		 * re-activating an already RF_ACTIVE resource must not
+		 * create a second kernel_map range, or the first one is
+		 * orphaned (permanent KVA leak + stale RW PTEs).
+		 */
+		if (rman_get_flags(r) & RF_ACTIVE)
+			return (rman_activate_resource(r));
 
 		if (rman_get_end(r) < 1024 * 1024) {
 			/*
@@ -446,6 +457,14 @@
 		rman_set_virtual(r, vaddr);
 		/* IBM-PC: the type of bus_space_handle_t is u_int */
 		rman_set_bushandle(r, (bus_space_handle_t) vaddr);
+		error = rman_activate_resource(r);
+		if (error != 0 && rman_get_end(r) >= 1024 * 1024) {
+			/* roll back the mapping we just created */
+			pmap_unmapdev((vm_offset_t)vaddr,
+			    (vm_size_t)rman_get_size(r));
+			rman_set_virtual(r, 0);
+		}
+		return (error);
 	}
 	return (rman_activate_resource(r));
 }