The function ip6_get_prevhdr() did return a pointer into a mbuf.
authorbluhm <bluhm@openbsd.org>
Thu, 1 Feb 2018 21:11:33 +0000 (21:11 +0000)
committerbluhm <bluhm@openbsd.org>
Thu, 1 Feb 2018 21:11:33 +0000 (21:11 +0000)
It was not guaranteed that the mbuf data was not somewhere else in
the chain.  So return an offset and do a proper mbuf pulldown.
found by Maxime Villard; from NetBSD; with markus@; OK deraadt@

sys/netinet6/frag6.c
sys/netinet6/ip6_input.c
sys/netinet6/ip6_var.h
sys/netinet6/raw_ip6.c

index 7b874e3..f3abef2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: frag6.c,v 1.81 2017/11/14 14:46:49 bluhm Exp $        */
+/*     $OpenBSD: frag6.c,v 1.82 2018/02/01 21:11:33 bluhm Exp $        */
 /*     $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $  */
 
 /*
@@ -422,14 +422,6 @@ frag6_input(struct mbuf **mp, int *offp, int proto, int af)
                goto dropfrag;
        }
 
-       /*
-        * Store NXT to the original.
-        */
-       {
-               u_int8_t *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
-               *prvnxtp = nxt;
-       }
-
        TAILQ_REMOVE(&frag6_queue, q6, ip6q_queue);
        frag6_nfrags -= q6->ip6q_nfrag;
        frag6_nfragpackets--;
@@ -445,6 +437,20 @@ frag6_input(struct mbuf **mp, int *offp, int proto, int af)
                m->m_pkthdr.len = plen;
        }
 
+       /*
+        * Restore NXT to the original.
+        */
+       {
+               int prvnxt = ip6_get_prevhdr(m, offset);
+               uint8_t *prvnxtp;
+
+               IP6_EXTHDR_GET(prvnxtp, uint8_t *, m, prvnxt,
+                   sizeof(*prvnxtp));
+               if (prvnxtp == NULL)
+                       goto dropfrag;
+               *prvnxtp = nxt;
+       }
+
        ip6stat_inc(ip6s_reassembled);
 
        /*
index 6f07b36..b7dc628 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_input.c,v 1.210 2017/11/23 13:45:46 mpi Exp $     */
+/*     $OpenBSD: ip6_input.c,v 1.211 2018/02/01 21:11:33 bluhm Exp $   */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -1188,50 +1188,44 @@ ip6_pullexthdr(struct mbuf *m, size_t off, int nxt)
 }
 
 /*
- * Get pointer to the previous header followed by the header
+ * Get offset to the previous header followed by the header
  * currently processed.
- * XXX: This function supposes that
- *     M includes all headers,
- *     the next header field and the header length field of each header
- *     are valid, and
- *     the sum of each header length equals to OFF.
- * Because of these assumptions, this function must be called very
- * carefully. Moreover, it will not be used in the near future when
- * we develop `neater' mechanism to process extension headers.
  */
-u_int8_t *
+int
 ip6_get_prevhdr(struct mbuf *m, int off)
 {
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
 
-       if (off == sizeof(struct ip6_hdr))
-               return (&ip6->ip6_nxt);
-       else {
-               int len, nxt;
-               struct ip6_ext *ip6e = NULL;
+       if (off == sizeof(struct ip6_hdr)) {
+               return offsetof(struct ip6_hdr, ip6_nxt);
+       } else if (off < sizeof(struct ip6_hdr)) {
+               panic("%s: off < sizeof(struct ip6_hdr)", __func__);
+       } else {
+               int len, nlen, nxt;
+               struct ip6_ext ip6e;
 
                nxt = ip6->ip6_nxt;
                len = sizeof(struct ip6_hdr);
+               nlen = 0;
                while (len < off) {
-                       ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
+                       m_copydata(m, len, sizeof(ip6e), (caddr_t)&ip6e);
 
                        switch (nxt) {
                        case IPPROTO_FRAGMENT:
-                               len += sizeof(struct ip6_frag);
+                               nlen = sizeof(struct ip6_frag);
                                break;
                        case IPPROTO_AH:
-                               len += (ip6e->ip6e_len + 2) << 2;
+                               nlen = (ip6e.ip6e_len + 2) << 2;
                                break;
                        default:
-                               len += (ip6e->ip6e_len + 1) << 3;
+                               nlen = (ip6e.ip6e_len + 1) << 3;
                                break;
                        }
-                       nxt = ip6e->ip6e_nxt;
+                       len += nlen;
+                       nxt = ip6e.ip6e_nxt;
                }
-               if (ip6e)
-                       return (&ip6e->ip6e_nxt);
-               else
-                       return NULL;
+
+               return (len - nlen);
        }
 }
 
index 370f23f..2e62ac0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_var.h,v 1.81 2017/11/05 13:19:59 florian Exp $    */
+/*     $OpenBSD: ip6_var.h,v 1.82 2018/02/01 21:11:33 bluhm Exp $      */
 /*     $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $        */
 
 /*
@@ -303,7 +303,7 @@ int ip6_input_if(struct mbuf **, int *, int, int, struct ifnet *);
 void   ip6_freepcbopts(struct ip6_pktopts *);
 void   ip6_freemoptions(struct ip6_moptions *);
 int    ip6_unknown_opt(u_int8_t *, struct mbuf *, int);
-u_int8_t *ip6_get_prevhdr(struct mbuf *, int);
+int    ip6_get_prevhdr(struct mbuf *, int);
 int    ip6_nexthdr(struct mbuf *, int, int, int *);
 int    ip6_lasthdr(struct mbuf *, int, int, int *);
 int    ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *);
index 8824f88..464e440 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: raw_ip6.c,v 1.125 2017/12/04 13:40:35 bluhm Exp $     */
+/*     $OpenBSD: raw_ip6.c,v 1.126 2018/02/01 21:11:33 bluhm Exp $     */
 /*     $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $        */
 
 /*
@@ -236,10 +236,10 @@ rip6_input(struct mbuf **mp, int *offp, int proto, int af)
                if (proto == IPPROTO_NONE || proto == IPPROTO_ICMPV6) {
                        m_freem(m);
                } else {
-                       u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
+                       int prvnxt = ip6_get_prevhdr(m, *offp);
+
                        icmp6_error(m, ICMP6_PARAM_PROB,
-                           ICMP6_PARAMPROB_NEXTHEADER,
-                           prvnxtp - mtod(m, u_int8_t *));
+                           ICMP6_PARAMPROB_NEXTHEADER, prvnxt);
                }
                counters = counters_enter(&ref, ip6counters);
                counters[ip6s_delivered]--;