diff options
author | krw <krw@openbsd.org> | 2016-02-03 14:48:36 +0000 |
---|---|---|
committer | krw <krw@openbsd.org> | 2016-02-03 14:48:36 +0000 |
commit | b4e2b63915f513b76fc044a8aa14753d8973493c (patch) | |
tree | e5da87c2e24fac50b565f16406aa41b327228483 /usr.sbin/dhcrelay | |
parent | Increase the RPC buffer once more to 4096 bytes. The guestinfo.ovfEnv (diff) | |
download | wireguard-openbsd-b4e2b63915f513b76fc044a8aa14753d8973493c.tar.xz wireguard-openbsd-b4e2b63915f513b76fc044a8aa14753d8973493c.zip |
be very careful accepting packets via bpf. First check that the
fixed part of the IP header is completely present before using its
header length field. Then use the data in the IP header to ensure
the entire IP packet is present. Then check that the entire UDP header
is present. Then use the data in the UDP header to ensure all the
data it thinks is present is actually present.
Started when tj@ and a few others noticed ISC "DHCP CVE-2015-8605:
UDP payload length not properly checked".
ok sthen@ henning@
Diffstat (limited to 'usr.sbin/dhcrelay')
-rw-r--r-- | usr.sbin/dhcrelay/packet.c | 35 |
1 files changed, 28 insertions, 7 deletions
diff --git a/usr.sbin/dhcrelay/packet.c b/usr.sbin/dhcrelay/packet.c index 99bff01f767..15c32c4612a 100644 --- a/usr.sbin/dhcrelay/packet.c +++ b/usr.sbin/dhcrelay/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.9 2016/02/02 23:18:16 sthen Exp $ */ +/* $OpenBSD: packet.c,v 1.10 2016/02/03 14:48:36 krw Exp $ */ /* Packet assembly code, originally contributed by Archie Cobbs. */ @@ -181,7 +181,7 @@ decode_udp_ip_header(struct interface_info *interface, unsigned char *buf, struct ip *ip; struct udphdr *udp; unsigned char *data; - u_int32_t ip_len = (buf[bufix] & 0xf) << 2; + u_int32_t ip_len; u_int32_t sum, usum; static unsigned int ip_packets_seen; static unsigned int ip_packets_bad_checksum; @@ -191,11 +191,16 @@ decode_udp_ip_header(struct interface_info *interface, unsigned char *buf, static unsigned int udp_packets_length_overflow; int len; + /* Assure that an entire IP header is within the buffer. */ + if (sizeof(*ip) > buflen) + return (-1); + ip_len = (buf[bufix] & 0xf) << 2; + if (ip_len > buflen) + return (-1); ip = (struct ip *)(buf + bufix); - udp = (struct udphdr *)(buf + bufix + ip_len); + ip_packets_seen++; /* Check the IP header checksum - it should be zero. */ - ip_packets_seen++; if (wrapsum(checksum(buf + bufix, ip_len, 0)) != 0) { ip_packets_bad_checksum++; if (ip_packets_seen > 4 && ip_packets_bad_checksum != 0 && @@ -207,20 +212,36 @@ decode_udp_ip_header(struct interface_info *interface, unsigned char *buf, return (-1); } + memcpy(&from->sin_addr, &ip->ip_src, sizeof(from->sin_addr)); + +#ifdef DEBUG if (ntohs(ip->ip_len) != buflen) debug("ip length %d disagrees with bytes received %d.", ntohs(ip->ip_len), buflen); +#endif - memcpy(&from->sin_addr, &ip->ip_src, 4); + /* Assure that the entire IP packet is within the buffer. */ + if (ntohs(ip->ip_len) > buflen) + return (-1); + + /* Assure that the UDP header is within the buffer. */ + if (ip_len + sizeof(*udp) > buflen) + return (-1); + udp = (struct udphdr *)(buf + bufix + ip_len); + udp_packets_seen++; + + /* Assure that the entire UDP packet is within the buffer. */ + if (ip_len + ntohs(udp->uh_ulen) > buflen) + return (-1); + data = buf + bufix + ip_len + sizeof(*udp); /* * Compute UDP checksums, including the ``pseudo-header'', the * UDP header and the data. If the UDP checksum field is zero, * we're not supposed to do a checksum. */ - data = buf + bufix + ip_len + sizeof(*udp); - len = ntohs(udp->uh_ulen) - sizeof(*udp); udp_packets_length_checked++; + len = ntohs(udp->uh_ulen) - sizeof(*udp); if ((len < 0) || (len + data > buf + bufix + buflen)) { udp_packets_length_overflow++; if (udp_packets_length_checked > 4 && |