untrusted comment: signature from openbsd 6.2 base secret key RWRVWzAMgtyg7gRLOEq05ScMhvGwVOtOWgAgzELGN8wwfvx3CbSBYSKwXo7xr/PC444JXfTnnefmn6xgl/UMAvgnWeLL+BN/PwA= OpenBSD 6.2 errata 005, February 2nd, 2018: Specially crafted IPsec AH packets with IP options or IPv6 extension headers could crash or hang the kernel. Apply by doing: signify -Vep /etc/signify/openbsd-62-base.pub -x 005_ahopts.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/netinet/ip_ah.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_ah.c,v retrieving revision 1.131 diff -u -p -r1.131 ip_ah.c --- sys/netinet/ip_ah.c 11 Aug 2017 21:24:19 -0000 1.131 +++ sys/netinet/ip_ah.c 1 Feb 2018 19:15:45 -0000 @@ -202,7 +202,7 @@ ah_massage_headers(struct mbuf **m0, int #ifdef INET6 struct ip6_ext *ip6e; struct ip6_hdr ip6; - int ad, alloc, nxt; + int ad, alloc, nxt, noff; #endif /* INET6 */ switch (proto) { @@ -226,7 +226,7 @@ ah_massage_headers(struct mbuf **m0, int ip->ip_sum = 0; ip->ip_off = 0; - ptr = mtod(m, unsigned char *) + sizeof(struct ip); + ptr = mtod(m, unsigned char *); /* IPv4 option processing */ for (off = sizeof(struct ip); off < skip;) { @@ -293,10 +293,12 @@ ah_massage_headers(struct mbuf **m0, int * what the destination's IP header * will look like. */ - if (out) - bcopy(ptr + off + ptr[off + 1] - + if (out && + ptr[off + 1] >= 2 + sizeof(struct in_addr)) + memcpy(&ip->ip_dst, + ptr + off + ptr[off + 1] - sizeof(struct in_addr), - &(ip->ip_dst), sizeof(struct in_addr)); + sizeof(struct in_addr)); /* FALLTHROUGH */ default: @@ -312,7 +314,7 @@ ah_massage_headers(struct mbuf **m0, int /* Zeroize all other options. */ count = ptr[off + 1]; - memcpy(ptr, ipseczeroes, count); + memset(ptr + off, 0, count); off += count; break; } @@ -389,57 +391,46 @@ ah_massage_headers(struct mbuf **m0, int nxt = ip6.ip6_nxt & 0xff; /* Next header type. */ for (off = 0; off < skip - sizeof(struct ip6_hdr);) { + if (off + sizeof(struct ip6_ext) > + skip - sizeof(struct ip6_hdr)) + goto error6; + ip6e = (struct ip6_ext *)(ptr + off); + switch (nxt) { case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: - ip6e = (struct ip6_ext *) (ptr + off); + noff = off + ((ip6e->ip6e_len + 1) << 3); + + /* Sanity check. */ + if (noff > skip - sizeof(struct ip6_hdr)) + goto error6; /* - * Process the mutable/immutable - * options -- borrows heavily from the - * KAME code. + * Zero out mutable options. */ for (count = off + sizeof(struct ip6_ext); - count < off + ((ip6e->ip6e_len + 1) << 3);) { + count < noff;) { if (ptr[count] == IP6OPT_PAD1) { count++; continue; /* Skip padding. */ } - /* Sanity check. */ - if (count > off + - ((ip6e->ip6e_len + 1) << 3)) { - ahstat.ahs_hdrops++; - m_freem(m); - - /* Free, if we allocated. */ - if (alloc) - free(ptr, M_XDATA, 0); - return EINVAL; - } - - ad = ptr[count + 1]; + if (count + 2 > noff) + goto error6; + ad = ptr[count + 1] + 2; + if (count + ad > noff) + goto error6; /* If mutable option, zeroize. */ if (ptr[count] & IP6OPT_MUTABLE) - memcpy(ptr + count, ipseczeroes, - ptr[count + 1]); + memset(ptr + count, 0, ad); count += ad; - - /* Sanity check. */ - if (count > - skip - sizeof(struct ip6_hdr)) { - ahstat.ahs_hdrops++; - m_freem(m); - - /* Free, if we allocated. */ - if (alloc) - free(ptr, M_XDATA, 0); - return EINVAL; - } } + if (count != noff) + goto error6; + /* Advance. */ off += ((ip6e->ip6e_len + 1) << 3); nxt = ip6e->ip6e_nxt; @@ -453,7 +444,6 @@ ah_massage_headers(struct mbuf **m0, int { struct ip6_rthdr *rh; - ip6e = (struct ip6_ext *) (ptr + off); rh = (struct ip6_rthdr *)(ptr + off); /* * must adjust content to make it look like @@ -498,6 +488,7 @@ ah_massage_headers(struct mbuf **m0, int default: DPRINTF(("ah_massage_headers(): unexpected " "IPv6 header type %d\n", off)); +error6: if (alloc) free(ptr, M_XDATA, 0); ahstat.ahs_hdrops++;