⬢ DragonFlyBSD Kernel Audit
DF-3310 / fix.diff
← back to finding ↓ download raw
--- 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);