Hi,

The checksum of a ICMP "need to frag" packet for TCP was wrong when
created from a ICMP6 "too big" packet.  The function pf_change_icmp_af()
has code to adjust the pseudo-header checksum in the ICMP6 case,
but pf_test_state_icmp() changed the proto before the case was
entered.

So call pf_change_icmp_af() before the pd->proto is converted in
the TCP and UDP payload case like it was already done for ICMP and
ICMP6 payload case.

This was found by the sys/net/pf_forward regress test.

My printf debugging revealed that dlen is positive and d may be
negative.  So declare the variables with the correct sign in
pf_change_icmp_af().

ok?

bluhm

Index: net/pf.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf.c,v
retrieving revision 1.989
diff -u -p -r1.989 pf.c
--- net/pf.c    9 Oct 2016 18:01:57 -0000       1.989
+++ net/pf.c    17 Oct 2016 20:00:41 -0000
@@ -2340,7 +2340,8 @@ pf_change_icmp_af(struct mbuf *m, int ip
        struct mbuf             *n = NULL;
        struct ip               *ip4;
        struct ip6_hdr          *ip6;
-       u_int                    hlen, ohlen, d;
+       u_int                    hlen, ohlen, dlen;
+       int                      d;
 
        if (af == naf || (af != AF_INET && af != AF_INET6) ||
            (naf != AF_INET && naf != AF_INET6))
@@ -2417,7 +2418,7 @@ pf_change_icmp_af(struct mbuf *m, int ip
 
        if (pd->proto == IPPROTO_ICMPV6) {
                /* fixup pseudo-header */
-               int dlen = pd->tot_len - pd->off;
+               dlen = pd->tot_len - pd->off;
                pf_cksum_fixup(pd->pcksum,
                    htons(dlen), htons(dlen + d), pd->proto);
        }
@@ -5104,6 +5105,10 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                        m_copyback(pd->m, pd->off,
                                            sizeof(struct icmp6_hdr),
                                            pd->hdr.icmp6, M_NOWAIT);
+                                       if (pf_change_icmp_af(pd->m, ipoff2,
+                                           pd, &pd2, &nk->addr[sidx],
+                                           &nk->addr[didx], pd->af, nk->af))
+                                               return (PF_DROP);
                                        if (nk->af == AF_INET)
                                                pd->proto = IPPROTO_ICMP;
                                        else
@@ -5117,11 +5122,6 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                            &nk->addr[pd2.didx], nk->af);
                                        pd->naf = nk->af;
 
-                                       if (pf_change_icmp_af(pd->m, ipoff2,
-                                           pd, &pd2, &nk->addr[sidx],
-                                           &nk->addr[didx], pd->af, nk->af))
-                                               return (PF_DROP);
-
                                        pf_patch_16(pd,
                                            &th.th_sport, nk->port[sidx]);
                                        pf_patch_16(pd,
@@ -5220,6 +5220,10 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                        m_copyback(pd->m, pd->off,
                                            sizeof(struct icmp6_hdr),
                                            pd->hdr.icmp6, M_NOWAIT);
+                                       if (pf_change_icmp_af(pd->m, ipoff2,
+                                           pd, &pd2, &nk->addr[sidx],
+                                           &nk->addr[didx], pd->af, nk->af))
+                                               return (PF_DROP);
                                        if (nk->af == AF_INET)
                                                pd->proto = IPPROTO_ICMP;
                                        else
@@ -5232,11 +5236,6 @@ pf_test_state_icmp(struct pf_pdesc *pd, 
                                        PF_ACPY(&pd->ndaddr,
                                            &nk->addr[pd2.didx], nk->af);
                                        pd->naf = nk->af;
-
-                                       if (pf_change_icmp_af(pd->m, ipoff2,
-                                           pd, &pd2, &nk->addr[sidx],
-                                           &nk->addr[didx], pd->af, nk->af))
-                                               return (PF_DROP);
 
                                        pf_patch_16(pd,
                                            &uh.uh_sport, nk->port[sidx]);

Reply via email to