untrusted comment: signature from openbsd 6.2 base secret key RWRVWzAMgtyg7hrX0W3MfBjHCqxXfZK8hxg53pU2kHsLGqoHEvQJr73pVWZIY3neMUmT4lSsyoaTsmV4XVSFMXhOrXNlYt/B9QA= OpenBSD 6.2 errata 006, February 2nd, 2018: Processing IPv6 fragments could incorrectly access memory of a mbuf chain that is not within a mbuf. This may crash the kernel. Apply by doing: signify -Vep /etc/signify/openbsd-62-base.pub -x 006_prevhdr.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install a new kernel: KK=`sysctl -n kern.osversion | cut -d# -f1` cd /usr/src/sys/arch/`machine`/compile/$KK make obj make config make make install Index: sys/netinet6/frag6.c =================================================================== RCS file: /cvs/src/sys/netinet6/frag6.c,v retrieving revision 1.74 diff -u -p -r1.74 frag6.c --- sys/netinet6/frag6.c 16 May 2017 12:24:02 -0000 1.74 +++ sys/netinet6/frag6.c 1 Feb 2018 19:18:07 -0000 @@ -476,14 +476,6 @@ frag6_input(struct mbuf **mp, int *offp, 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; free(q6, M_FTABLE, sizeof(*q6)); @@ -494,6 +486,20 @@ frag6_input(struct mbuf **mp, int *offp, for (t = m; t; t = t->m_next) plen += t->m_len; 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: sys/netinet6/ip6_input.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.202 diff -u -p -r1.202 ip6_input.c --- sys/netinet6/ip6_input.c 22 Aug 2017 15:02:34 -0000 1.202 +++ sys/netinet6/ip6_input.c 1 Feb 2018 19:18:07 -0000 @@ -1189,50 +1189,44 @@ ip6_pullexthdr(struct mbuf *m, size_t of } /* - * 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: sys/netinet6/ip6_var.h =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_var.h,v retrieving revision 1.78 diff -u -p -r1.78 ip6_var.h --- sys/netinet6/ip6_var.h 13 Jul 2017 17:17:27 -0000 1.78 +++ sys/netinet6/ip6_var.h 1 Feb 2018 19:18:07 -0000 @@ -305,7 +305,7 @@ int ip6_input_if(struct mbuf **, int *, 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: sys/netinet6/raw_ip6.c =================================================================== RCS file: /cvs/src/sys/netinet6/raw_ip6.c,v retrieving revision 1.119 diff -u -p -r1.119 raw_ip6.c --- sys/netinet6/raw_ip6.c 5 Sep 2017 07:59:11 -0000 1.119 +++ sys/netinet6/raw_ip6.c 1 Feb 2018 19:18:07 -0000 @@ -229,10 +229,10 @@ rip6_input(struct mbuf **mp, int *offp, 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]--;