summaryrefslogtreecommitdiffstats
path: root/usr.sbin/dhcrelay
diff options
context:
space:
mode:
authorkrw <krw@openbsd.org>2016-02-03 14:48:36 +0000
committerkrw <krw@openbsd.org>2016-02-03 14:48:36 +0000
commitb4e2b63915f513b76fc044a8aa14753d8973493c (patch)
treee5da87c2e24fac50b565f16406aa41b327228483 /usr.sbin/dhcrelay
parentIncrease the RPC buffer once more to 4096 bytes. The guestinfo.ovfEnv (diff)
downloadwireguard-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.c35
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 &&