diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -409,14 +409,14 @@ static void pf_packet_rework_nat(struct pf_pdesc *, int, struct pf_state_key *); #ifdef INET -static void pf_route(struct pf_krule *, +static int pf_route(struct pf_krule *, struct ifnet *, struct pf_kstate *, struct pf_pdesc *, struct inpcb *); #endif /* INET */ #ifdef INET6 static void pf_change_a6(struct pf_addr *, u_int16_t *, struct pf_addr *, u_int8_t); -static void pf_route6(struct pf_krule *, +static int pf_route6(struct pf_krule *, struct ifnet *, struct pf_kstate *, struct pf_pdesc *, struct inpcb *); #endif /* INET6 */ @@ -8909,7 +8909,7 @@ } #ifdef INET -static void +static int pf_route(struct pf_krule *r, struct ifnet *oifp, struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) { @@ -8924,6 +8924,7 @@ uint16_t tmp; int r_dir; bool skip_test = false; + int action = PF_PASS; KASSERT(pd->m && r && oifp, ("%s: invalid parameters", __func__)); @@ -8945,6 +8946,7 @@ m0 = pd->m; pd->m = NULL; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad_locked; } @@ -8958,11 +8960,12 @@ } if (ifp == oifp) { /* When the 2nd interface is not skipped */ - return; + return (action); } else { m0 = pd->m; pd->m = NULL; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } } else { @@ -8970,7 +8973,7 @@ if (((m0 = m_dup(pd->m, M_NOWAIT)) == NULL)) { if (s) PF_STATE_UNLOCK(s); - return; + return (action); } } } else { @@ -8979,7 +8982,7 @@ pf_dummynet(pd, s, r, &pd->m); if (s) PF_STATE_UNLOCK(s); - return; + return (action); } else { if (r_dir == PF_IN) { skip_test = true; @@ -9019,6 +9022,7 @@ pf_send_icmp(m0, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, pd->af, r, pd->act.rtableid); + action = PF_DROP; goto bad_locked; } ip->ip_ttl -= IPTTLDEC; @@ -9065,6 +9069,7 @@ if (ifp == NULL) { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); goto bad; } @@ -9075,9 +9080,11 @@ if (pd->dir == PF_IN && !skip_test) { if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp, &pd->act) != PF_PASS) { + action = PF_DROP; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); goto bad; } else if (m0 == NULL) { + action = PF_DROP; SDT_PROBE1(pf, ip, route_to, drop, __LINE__); goto done; } @@ -9085,6 +9092,7 @@ DPFPRINTF(PF_DEBUG_URGENT, "%s: m0->m_len < sizeof(struct ip)", __func__); SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } ip = mtod(m0, struct ip *); @@ -9166,12 +9174,14 @@ ifp->if_mtu, pd->af, r, pd->act.rtableid); } SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist); if (error) { SDT_PROBE1(pf, ip, route_to, drop, __LINE__); + action = PF_DROP; goto bad; } @@ -9198,7 +9208,9 @@ done: if (pd->act.rt != PF_DUPTO) pd->m = NULL; - return; + else + action = PF_PASS; + return (action); bad_locked: if (s) @@ -9210,7 +9222,7 @@ #endif /* INET */ #ifdef INET6 -static void +static int pf_route6(struct pf_krule *r, struct ifnet *oifp, struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp) { @@ -9221,6 +9233,7 @@ struct ifnet *ifp = NULL; int r_dir; bool skip_test = false; + int action = PF_PASS; KASSERT(pd->m && r && oifp, ("%s: invalid parameters", __func__)); @@ -9241,6 +9254,7 @@ pd->pf_mtag->routed++ > 3) { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad_locked; } @@ -9255,10 +9269,11 @@ } if (ifp == oifp) { /* When the 2nd interface is not skipped */ - return; + return (action); } else { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9267,7 +9282,7 @@ if (((m0 = m_dup(pd->m, M_NOWAIT)) == NULL)) { if (s) PF_STATE_UNLOCK(s); - return; + return (action); } } } else { @@ -9276,7 +9291,7 @@ pf_dummynet(pd, s, r, &pd->m); if (s) PF_STATE_UNLOCK(s); - return; + return (action); } else { if (r_dir == PF_IN) { skip_test = true; @@ -9316,6 +9331,7 @@ pf_send_icmp(m0, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT, 0, pd->af, r, pd->act.rtableid); + action = PF_DROP; goto bad_locked; } ip6->ip6_hlim -= IPV6_HLIMDEC; @@ -9370,6 +9386,7 @@ if (ifp == NULL) { m0 = pd->m; pd->m = NULL; + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9380,9 +9397,11 @@ if (pd->dir == PF_IN && !skip_test) { if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT, ifp, &m0, inp, &pd->act) != PF_PASS) { + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } else if (m0 == NULL) { + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto done; } @@ -9390,6 +9409,7 @@ DPFPRINTF(PF_DEBUG_URGENT, "%s: m0->m_len < sizeof(struct ip6_hdr)", __func__); + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9465,6 +9485,7 @@ pf_send_icmp(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu, pd->af, r, pd->act.rtableid); } + action = PF_DROP; SDT_PROBE1(pf, ip6, route_to, drop, __LINE__); goto bad; } @@ -9472,7 +9493,9 @@ done: if (pd->act.rt != PF_DUPTO) pd->m = NULL; - return; + else + action = PF_PASS; + return (action); bad_locked: if (s) @@ -11028,15 +11051,18 @@ break; } #ifdef INET - if (pd.naf == AF_INET) - pf_route(r, kif->pfik_ifp, s, &pd, inp); + if (pd.naf == AF_INET) { + action = pf_route(r, kif->pfik_ifp, s, &pd, + inp); + } #endif /* INET */ #ifdef INET6 - if (pd.naf == AF_INET6) - pf_route6(r, kif->pfik_ifp, s, &pd, inp); + if (pd.naf == AF_INET6) { + action = pf_route6(r, kif->pfik_ifp, s, &pd, + inp); +} #endif /* INET6 */ *m0 = pd.m; - action = PF_PASS; goto out; break; default: @@ -11045,13 +11071,15 @@ #ifdef INET case AF_INET: /* pf_route() returns unlocked. */ - pf_route(r, kif->pfik_ifp, s, &pd, inp); + action = pf_route(r, kif->pfik_ifp, s, &pd, + inp); break; #endif /* INET */ #ifdef INET6 case AF_INET6: /* pf_route6() returns unlocked. */ - pf_route6(r, kif->pfik_ifp, s, &pd, inp); + action = pf_route6(r, kif->pfik_ifp, s, &pd, + inp); break; #endif /* INET6 */ } diff --git a/tests/sys/netpfil/pf/nat64.py b/tests/sys/netpfil/pf/nat64.py --- a/tests/sys/netpfil/pf/nat64.py +++ b/tests/sys/netpfil/pf/nat64.py @@ -326,3 +326,31 @@ packets = sp.sniff(iface=ifname, timeout=5) for r in packets: r.show() + + @pytest.mark.require_user("root") + @pytest.mark.require_progs(["scapy"]) + def test_ttl_zero(self): + """ + PR 288274: we can use an mbuf after free on TTL = 0 + """ + ifname = self.vnet.iface_alias_map["if1"].name + gw_mac = self.vnet.iface_alias_map["if1"].epairb.ether + ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1") + + import scapy.all as sp + + pkt = sp.Ether(dst=gw_mac) \ + / sp.IPv6(dst="64:ff9b::192.0.2.2", hlim=0) \ + / sp.SCTP(sport=1111, dport=2222) \ + / sp.SCTPChunkInit(init_tag=1, n_in_streams=1, n_out_streams=1, \ + a_rwnd=1500, params=[ \ + sp.SCTPChunkParamIPv4Addr() \ + ]) + pkt.show() + sp.hexdump(pkt) + s = DelayedSend(pkt, sendif=ifname) + + packets = sp.sniff(iface=ifname, timeout=5) + for r in packets: + r.show() +