DragonFlyBSD Kernel Audit
DF-2857 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -184,13 +184,24 @@
 	size_t size;
 
 	shm_handle = shmseg->shm_internal;
-	vm_object_deallocate(shm_handle->shm_object);
-	kfree((caddr_t)shm_handle, M_SHM);
-	shmseg->shm_internal = NULL;
 	size = round_page(shmseg->shm_segsz);
 	shm_committed -= btoc(size);
 	shm_nused--;
+	/*
+	 * Hide the segment and disconnect the handle BEFORE the teardown
+	 * below.  vm_object_deallocate() -> vm_object_terminate() can block
+	 * and yields (lwkt_user_yield() every 64 pages), which temporarily
+	 * releases shm_token.  Until SHMSEG_ALLOCATED is cleared,
+	 * shm_find_segment_by_shmid() (with the default shm_allow_removed=1)
+	 * still returns this mid-teardown segment, so a racing IPC_RMID or
+	 * shmat() re-enters shm_deallocate_segment() and double-deallocates
+	 * the vm_object (ref_count already 0) or attaches to the dying
+	 * object.
+	 */
 	shmseg->shm_perm.mode = SHMSEG_FREE;
+	shmseg->shm_internal = NULL;
+	vm_object_deallocate(shm_handle->shm_object);
+	kfree((caddr_t)shm_handle, M_SHM);
 }
 
 static int