Author: ae
Date: Mon Feb 12 13:52:58 2018
New Revision: 329158
URL: https://svnweb.freebsd.org/changeset/base/329158

Log:
  MFC r328876:
    Modify ip6_get_prevhdr() to be able use it safely.
  
    Instead of returning pointer to the previous header, return its offset.
    In frag6_input() use m_copyback() and determined offset to store next
    header instead of accessing to it by pointer and assuming that the memory
    is contiguous.
  
    In rip6_input() use offset returned by ip6_get_prevhdr() instead of
    calculating it from pointers arithmetic, because IP header can belong
    to another mbuf in the chain.
  
    Reported by:        Maxime Villard <max at m00nbsd dot net>

Modified:
  stable/10/sys/netinet6/frag6.c
  stable/10/sys/netinet6/ip6_input.c
  stable/10/sys/netinet6/ip6_var.h
  stable/10/sys/netinet6/raw_ip6.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/netinet6/frag6.c
==============================================================================
--- stable/10/sys/netinet6/frag6.c      Mon Feb 12 12:41:53 2018        
(r329157)
+++ stable/10/sys/netinet6/frag6.c      Mon Feb 12 13:52:58 2018        
(r329158)
@@ -579,10 +579,8 @@ insert:
        /*
         * Store NXT to the original.
         */
-       {
-               char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
-               *prvnxtp = nxt;
-       }
+       m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t),
+           (caddr_t)&nxt);
 
        frag6_remque(q6);
        V_frag6_nfrags -= q6->ip6q_nfrag;

Modified: stable/10/sys/netinet6/ip6_input.c
==============================================================================
--- stable/10/sys/netinet6/ip6_input.c  Mon Feb 12 12:41:53 2018        
(r329157)
+++ stable/10/sys/netinet6/ip6_input.c  Mon Feb 12 13:52:58 2018        
(r329158)
@@ -1677,49 +1677,39 @@ ip6_pullexthdr(struct mbuf *m, size_t off, int nxt)
 /*
  * Get pointer 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.
  */
-char *
+int
 ip6_get_prevhdr(struct mbuf *m, int off)
 {
-       struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+       struct ip6_ext ip6e;
+       struct ip6_hdr *ip6;
+       int len, nlen, nxt;
 
        if (off == sizeof(struct ip6_hdr))
-               return (&ip6->ip6_nxt);
-       else {
-               int len, nxt;
-               struct ip6_ext *ip6e = NULL;
+               return (offsetof(struct ip6_hdr, ip6_nxt));
+       if (off < sizeof(struct ip6_hdr))
+               panic("%s: off < sizeof(struct ip6_hdr)", __func__);
 
-               nxt = ip6->ip6_nxt;
-               len = sizeof(struct ip6_hdr);
-               while (len < off) {
-                       ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + len);
-
-                       switch (nxt) {
-                       case IPPROTO_FRAGMENT:
-                               len += sizeof(struct ip6_frag);
-                               break;
-                       case IPPROTO_AH:
-                               len += (ip6e->ip6e_len + 2) << 2;
-                               break;
-                       default:
-                               len += (ip6e->ip6e_len + 1) << 3;
-                               break;
-                       }
-                       nxt = ip6e->ip6e_nxt;
+       ip6 = mtod(m, struct ip6_hdr *);
+       nxt = ip6->ip6_nxt;
+       len = sizeof(struct ip6_hdr);
+       nlen = 0;
+       while (len < off) {
+               m_copydata(m, len, sizeof(ip6e), (caddr_t)&ip6e);
+               switch (nxt) {
+               case IPPROTO_FRAGMENT:
+                       nlen = sizeof(struct ip6_frag);
+                       break;
+               case IPPROTO_AH:
+                       nlen = (ip6e.ip6e_len + 2) << 2;
+                       break;
+               default:
+                       nlen = (ip6e.ip6e_len + 1) << 3;
                }
-               if (ip6e)
-                       return (&ip6e->ip6e_nxt);
-               else
-                       return NULL;
+               len += nlen;
+               nxt = ip6e.ip6e_nxt;
        }
+       return (len - nlen);
 }
 
 /*

Modified: stable/10/sys/netinet6/ip6_var.h
==============================================================================
--- stable/10/sys/netinet6/ip6_var.h    Mon Feb 12 12:41:53 2018        
(r329157)
+++ stable/10/sys/netinet6/ip6_var.h    Mon Feb 12 13:52:58 2018        
(r329158)
@@ -390,7 +390,7 @@ struct in6_ifaddr *ip6_getdstifaddr(struct mbuf *);
 void   ip6_freepcbopts(struct ip6_pktopts *);
 
 int    ip6_unknown_opt(u_int8_t *, struct mbuf *, int);
-char * 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 *);
 

Modified: stable/10/sys/netinet6/raw_ip6.c
==============================================================================
--- stable/10/sys/netinet6/raw_ip6.c    Mon Feb 12 12:41:53 2018        
(r329157)
+++ stable/10/sys/netinet6/raw_ip6.c    Mon Feb 12 13:52:58 2018        
(r329158)
@@ -328,12 +328,10 @@ rip6_input(struct mbuf **mp, int *offp, int proto)
                        RIP6STAT_INC(rip6s_nosockmcast);
                if (proto == IPPROTO_NONE)
                        m_freem(m);
-               else {
-                       char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
+               else
                        icmp6_error(m, ICMP6_PARAM_PROB,
                            ICMP6_PARAMPROB_NEXTHEADER,
-                           prvnxtp - mtod(m, char *));
-               }
+                           ip6_get_prevhdr(m, *offp));
                IP6STAT_DEC(ip6s_delivered);
        }
        return (IPPROTO_DONE);
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to