DF-2541 / fix.diff
diff --git a/sys/net/ip_mroute/ip_mroute.c b/sys/net/ip_mroute/ip_mroute.c @@ -1713,7 +1713,16 @@ struct ip *ip = mtod(m, struct ip *); int hlen = ip->ip_hl << 2; + /* + * Serialize against del_vif()/X_ip_mrouter_done(), which bzero() viftable + * entries and reset the last_encap_vif/last_encap_src cache under this + * token. Without the token a concurrent teardown can zero the cached vif + * between the validation walk and the last_encap_vif->v_ifp dereference + * below, producing a NULL function-pointer call in ip_input (DF-2541). + */ + lwkt_gettoken(&mroute_token); if (!have_encap_tunnel) { + lwkt_reltoken(&mroute_token); rip_input(mp, offp, proto); return(IPPROTO_DONE); } @@ -1729,6 +1738,7 @@ if (!IN_MULTICAST(ntohl(((struct ip *)((char *)ip+hlen))->ip_dst.s_addr))) { ++mrtstat.mrts_bad_tunnel; m_freem(m); + lwkt_reltoken(&mroute_token); return(IPPROTO_DONE); } if (ip->ip_src.s_addr != last_encap_src) { @@ -1752,6 +1762,7 @@ if (mrtdebug) log(LOG_DEBUG, "ip_mforward: no tunnel with %lx\n", (u_long)ntohl(ip->ip_src.s_addr)); + lwkt_reltoken(&mroute_token); return(IPPROTO_DONE); } @@ -1763,6 +1774,7 @@ m->m_pkthdr.rcvif = last_encap_vif->v_ifp; netisr_queue(NETISR_IP, m); + lwkt_reltoken(&mroute_token); return(IPPROTO_DONE); } |