--- a/sys/net/wg/if_wg.c +++ b/sys/net/wg/if_wg.c @@ -971,7 +971,14 @@ KKASSERT(lockstatus(&sc->sc_lock, curthread) == LK_EXCLUSIVE); - lockinit(&so->so_lock, "wg socket lock", 0, 0); + /* + * Serialize the close/install below against wg_send(), which holds + * so_lock shared while reading so_so4/so_so6. NOTE: so_lock is + * initialized exactly once in wg_clone_create(); re-running + * lockinit() here would zero lk_count under live holders and + * permanently corrupt the lock. + */ + lockmgr(&so->so_lock, LK_EXCLUSIVE); if (so->so_so4 != NULL) soclose(so->so_so4, 0); @@ -980,6 +987,7 @@ so->so_so4 = so4; so->so_so6 = so6; so->so_port = bound_port; + lockmgr(&so->so_lock, LK_RELEASE); return (0); @@ -1072,7 +1080,7 @@ } lockmgr(&so->so_lock, LK_RELEASE); - lockuninit(&so->so_lock); + /* so_lock is torn down with the softc in wg_clone_destroy(). */ } static int @@ -2821,6 +2829,7 @@ lockinit(&sc->sc_lock, "wg softc lock", 0, 0); lockinit(&sc->sc_aip_lock, "wg aip lock", 0, 0); + lockinit(&sc->sc_socket.so_lock, "wg socket lock", 0, 0); sc->sc_local = noise_local_alloc(); sc->sc_cookie = cookie_checker_alloc(); @@ -2908,6 +2917,9 @@ cookie_checker_free(sc->sc_cookie); noise_local_free(sc->sc_local); + /* All socket users are gone now; tear down the socket lock. */ + lockuninit(&sc->sc_socket.so_lock); + lockmgr(&wg_mtx, LK_EXCLUSIVE); LIST_REMOVE(sc, sc_entry); lockmgr(&wg_mtx, LK_RELEASE);