summaryrefslogtreecommitdiffstats
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
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@
-rw-r--r--sbin/dhclient/packet.c33
-rw-r--r--usr.sbin/dhcpd/packet.c37
-rw-r--r--usr.sbin/dhcrelay/packet.c35
3 files changed, 84 insertions, 21 deletions
diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c
index 38e327456ee..64704d05d7a 100644
--- a/sbin/dhclient/packet.c
+++ b/sbin/dhclient/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.28 2014/10/25 03:18:13 lteo Exp $ */
+/* $OpenBSD: packet.c,v 1.29 2016/02/03 14:48:36 krw Exp $ */
/* Packet assembly code, originally contributed by Archie Cobbs. */
@@ -108,7 +108,7 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from,
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 int ip_packets_seen;
static int ip_packets_bad_checksum;
@@ -118,11 +118,16 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from,
static 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 &&
@@ -134,22 +139,36 @@ decode_udp_ip_header(unsigned char *buf, int bufix, struct sockaddr_in *from,
return (-1);
}
+ memcpy(&from->sin_addr, &ip->ip_src, sizeof(from->sin_addr));
+
#ifdef DEBUG
if (ntohs(ip->ip_len) != buflen)
debug("ip length %hu disagrees with bytes received %d.",
ntohs(ip->ip_len), buflen);
#endif
- memcpy(&from->sin_addr, &ip->ip_src, sizeof(from->sin_addr));
+ /* 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 &&
diff --git a/usr.sbin/dhcpd/packet.c b/usr.sbin/dhcpd/packet.c
index c35bd2b370b..4b0ac2cf653 100644
--- a/usr.sbin/dhcpd/packet.c
+++ b/usr.sbin/dhcpd/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.9 2014/10/25 03:23:49 lteo Exp $ */
+/* $OpenBSD: packet.c,v 1.10 2016/02/03 14:48:36 krw Exp $ */
/* Packet assembly code, originally contributed by Archie Cobbs. */
@@ -162,7 +162,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;
@@ -172,11 +172,17 @@ 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 &&
@@ -188,20 +194,37 @@ 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 &&
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 &&