DragonFlyBSD Kernel Audit
DF-2677 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -359,6 +359,17 @@
 	else
 		align = PAGE_SIZE;
 
+	/*
+	 * Increment the attach count BEFORE any operation that can block.
+	 * While blocked (e.g. inside vm_object_hold() below) lwkt drops
+	 * shm_token, and a concurrent shmctl(IPC_RMID) would otherwise see
+	 * shm_nattch == 0 and deallocate the segment (terminating the VM
+	 * object) out from under this attach, leaving a reference on an
+	 * OBJ_DEAD object (vm_object_terminate2 panic) or corrupting a
+	 * recycled shmseg's accounting.
+	 */
+	shmseg->shm_nattch++;
+
 	shm_handle = shmseg->shm_internal;
 	vm_object_hold(shm_handle->shm_object);
 	vm_object_reference_locked(shm_handle->shm_object);
@@ -373,6 +384,12 @@
 	if (rv != KERN_SUCCESS) {
                 vm_object_deallocate(shm_handle->shm_object);
 		shmmap_s->reserved = 0;
+		if ((--shmseg->shm_nattch <= 0) &&
+		    (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
+			/* deferred deallocate from IPC_RMID */
+			shm_deallocate_segment(shmseg);
+			shm_last_free = IPCID_TO_IX(uap->shmid);
+		}
 		error = ENOMEM;
 		goto done;
 	}
@@ -385,7 +402,6 @@
 	shmmap_s->reserved = 0;
 	shmseg->shm_lpid = p->p_pid;
 	shmseg->shm_atime = time_second;
-	shmseg->shm_nattch++;
 	sysmsg->sysmsg_resultp = (void *)attach_va;
 	error = 0;
 done: