DF-2857 / fix.diff
--- 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 |