DragonFlyBSD Kernel Audit
DF-0303 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -506,6 +506,16 @@
 	uint8_t version = CARP_VERSION, type = CARP_ADVERTISEMENT;
 	uint8_t vhid = sc->sc_vhid & 0xff;
 	int i;
+
+	/* DF-0303: Serialize access to sc_sha1/sc_pad. carp_hmac_prepare()
+	 * rewrites these in-place and can race with carp_hmac_generate()/
+	 * carp_hmac_verify() on another CPU, producing a torn SHA1_CTX that
+	 * causes legitimate advertisements to fail HMAC verification.
+	 * crit_enter() prevents preemption on this CPU; combined with
+	 * ASSERT_NETISR0 serialization of the input path, this closes the
+	 * torn-read window.
+	 */
+	crit_enter();
 #ifdef INET6
 	struct ifaddr_container *ifac;
 	struct in6_addr in6;
@@ -550,6 +560,8 @@
 	/* convert ipad to opad */
 	for (i = 0; i < sizeof(sc->sc_pad); i++)
 		sc->sc_pad[i] ^= 0x36 ^ 0x5c;
+
+	crit_exit();
 }
 
 static void
@@ -558,8 +570,13 @@
 {
 	SHA1_CTX sha1ctx;
 
+	/* DF-0303: Protect against concurrent carp_hmac_prepare() tearing
+	 * sc_sha1. crit_enter() prevents preemption on this CPU.
+	 */
+	crit_enter();
 	/* fetch first half of inner hash */
 	bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx));
+	crit_exit();
 
 	SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter));
 	SHA1Final(md, &sha1ctx);