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);