Module Name: src Committed By: martin Date: Sat Mar 31 10:38:53 UTC 2018
Modified Files: src/sys/netinet [netbsd-8]: ip_icmp.c Log Message: Pull up following revision(s) (requested by maxv in ticket #675): sys/netinet/ip_icmp.c: revision 1.168 Fix a possible buffer overflow in the IPv4 _ctlinput functions. In _icmp_input we are guaranteeing that the ICMP_ADVLENMIN-byte area starting from 'icp' is contiguous. ICMP_ADVLENMIN = 8 + sizeof(struct ip) + 8 = 36 But the _ctlinput functions (eg udp_ctlinput) expect the area to be larger. These functions read at: (uint8_t *)icp + 8 + (icp->icmp_ip.ip_hl << 2) which can be crafted to be: (uint8_t *)icp + 68 So we end up reading 'icp+68' while the valid area ended at 'icp+36'. Having said that, it seems pretty complicated to trigger this bug; it would have to be a fragmented packet with half of the ICMP header in the first fragment, and we would need to have a driver that did not allocate a cluster for the first mbuf of the chain. The check of icmplen against ICMP_ADVLEN(icp) was not sufficient: while it did guarantee that the ICMP header fit the chain, it did not guarantee that it fit 'm'. Fix this bug by pulling up to hlen+ICMP_ADVLEN(icp). No need to log an error. Rebase the pointers afterwards. To generate a diff of this commit: cvs rdiff -u -r1.161 -r1.161.6.1 src/sys/netinet/ip_icmp.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet/ip_icmp.c diff -u src/sys/netinet/ip_icmp.c:1.161 src/sys/netinet/ip_icmp.c:1.161.6.1 --- src/sys/netinet/ip_icmp.c:1.161 Fri Mar 31 06:49:44 2017 +++ src/sys/netinet/ip_icmp.c Sat Mar 31 10:38:53 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_icmp.c,v 1.161 2017/03/31 06:49:44 ozaki-r Exp $ */ +/* $NetBSD: ip_icmp.c,v 1.161.6.1 2018/03/31 10:38:53 martin Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -94,7 +94,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.161 2017/03/31 06:49:44 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.161.6.1 2018/03/31 10:38:53 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_ipsec.h" @@ -541,6 +541,14 @@ _icmp_input(struct mbuf *m, int hlen, in ICMP_STATINC(ICMP_STAT_BADLEN); goto freeit; } + if (m->m_len < hlen + ICMP_ADVLEN(icp)) { + m = m_pullup(m, hlen + ICMP_ADVLEN(icp)); + if (m == NULL) + goto freeit; + } + ip = mtod(m, struct ip *); + icp = (struct icmp *)(mtod(m, uint8_t *) + hlen); + if (IN_MULTICAST(icp->icmp_ip.ip_dst.s_addr)) goto badcode; #ifdef ICMPPRINTFS