dhcp: CVE-2015-8605

ISC DHCP allows remote attackers to cause a denial of
service (application crash) via an invalid length field
in a UDP IPv4 packet.

(From OE-Core rev: 43f2cfdf63fb70e3c2da0224221dae63b05477df)

Signed-off-by: Mariano Lopez <mariano.lopez@linux.intel.com>
Signed-off-by: Joshua Lock <joshua.g.lock@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Mariano Lopez 2016-03-11 08:47:09 +00:00 committed by Richard Purdie
parent 900d7d6b59
commit dad3b97a9a
3 changed files with 234 additions and 0 deletions

View File

@ -0,0 +1,101 @@
Solves CVE-2015-8605 that caused DoS when an invalid length field in IPv4 UDP
was received by the server.
Upstream-Status: Backport (v4.3.3p1)
CVE: CVE-2015-8605
From: https://source.isc.org/cgi-bin/gitweb.cgi?p=dhcp.git;a=commit;h=4ce21cb6301d665de01c1a6209e40f5f35072c0c
Signed-off-by: Mariano Lopez <mariano.lopez@linux.intel.com>
=======================================================================
diff --git a/common/packet.c b/common/packet.c
index b530432..e600e37 100644
--- a/common/packet.c
+++ b/common/packet.c
@@ -220,7 +220,28 @@ ssize_t decode_hw_header (interface, buf, bufix, from)
}
}
-/* UDP header and IP header decoded together for convenience. */
+/*!
+ *
+ * \brief UDP header and IP header decoded together for convenience.
+ *
+ * Attempt to decode the UDP and IP headers and, if necessary, checksum
+ * the packet.
+ *
+ * \param inteface - the interface on which the packet was recevied
+ * \param buf - a pointer to the buffer for the received packet
+ * \param bufix - where to start processing the buffer, previous
+ * routines may have processed parts of the buffer already
+ * \param from - space to return the address of the packet sender
+ * \param buflen - remaining length of the buffer, this will have been
+ * decremented by bufix by the caller
+ * \param rbuflen - space to return the length of the payload from the udp
+ * header
+ * \param csum_ready - indication if the checksum is valid for use
+ * non-zero indicates the checksum should be validated
+ *
+ * \return - the index to the first byte of the udp payload (that is the
+ * start of the DHCP packet
+ */
ssize_t
decode_udp_ip_header(struct interface_info *interface,
@@ -231,7 +252,7 @@ decode_udp_ip_header(struct interface_info *interface,
unsigned char *data;
struct ip ip;
struct udphdr udp;
- unsigned char *upp, *endbuf;
+ unsigned char *upp;
u_int32_t ip_len, ulen, pkt_len;
static unsigned int ip_packets_seen = 0;
static unsigned int ip_packets_bad_checksum = 0;
@@ -241,11 +262,8 @@ decode_udp_ip_header(struct interface_info *interface,
static unsigned int udp_packets_length_overflow = 0;
unsigned len;
- /* Designate the end of the input buffer for bounds checks. */
- endbuf = buf + bufix + buflen;
-
/* Assure there is at least an IP header there. */
- if ((buf + bufix + sizeof(ip)) > endbuf)
+ if (sizeof(ip) > buflen)
return -1;
/* Copy the IP header into a stack aligned structure for inspection.
@@ -257,13 +275,17 @@ decode_udp_ip_header(struct interface_info *interface,
ip_len = (*upp & 0x0f) << 2;
upp += ip_len;
- /* Check the IP packet length. */
+ /* Check packet lengths are within the buffer:
+ * first the ip header (ip_len)
+ * then the packet length from the ip header (pkt_len)
+ * then the udp header (ip_len + sizeof(udp)
+ * We are liberal in what we accept, the udp payload should fit within
+ * pkt_len, but we only check against the full buffer size.
+ */
pkt_len = ntohs(ip.ip_len);
- if (pkt_len > buflen)
- return -1;
-
- /* Assure after ip_len bytes that there is enough room for a UDP header. */
- if ((upp + sizeof(udp)) > endbuf)
+ if ((ip_len > buflen) ||
+ (pkt_len > buflen) ||
+ ((ip_len + sizeof(udp)) > buflen))
return -1;
/* Copy the UDP header into a stack aligned structure for inspection. */
@@ -284,7 +306,8 @@ decode_udp_ip_header(struct interface_info *interface,
return -1;
udp_packets_length_checked++;
- if ((upp + ulen) > endbuf) {
+ /* verify that the payload length from the udp packet fits in the buffer */
+ if ((ip_len + ulen) > buflen) {
udp_packets_length_overflow++;
if (((udp_packets_length_checked > 4) &&
(udp_packets_length_overflow != 0)) &&

View File

@ -0,0 +1,131 @@
This patch is needed in order to apply the patch for CVE-2015-8605.
Upstream-Status: Backport (4.3.2+)
From: https://source.isc.org/cgi-bin/gitweb.cgi?p=dhcp.git;a=commit;h=0ce1aa94454ce9b50d592c08d7e0c559d38d3bc5
Signed-off-by: Mariano Lopez <mariano.lopez@linux.intel.com>
---
From 0ce1aa94454ce9b50d592c08d7e0c559d38d3bc5 Mon Sep 17 00:00:00 2001
From: Thomas Markwalder <tmark@isc.org>
Date: Mon, 8 Sep 2014 09:31:32 -0400
Subject: [PATCH] [master] Corrected error in UDP bad packet logging
Merges in rt36897
---
common/packet.c | 55 +++++++++++++++++++++++++++++++++++--------------------
1 file changed, 35 insertions(+), 20 deletions(-)
diff --git a/common/packet.c b/common/packet.c
index 45e96e8..7460f3d 100644
--- a/common/packet.c
+++ b/common/packet.c
@@ -3,7 +3,7 @@
Packet assembly code, originally contributed by Archie Cobbs. */
/*
- * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2009,2012,2014 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-2003 by Internet Software Consortium
*
@@ -234,12 +234,12 @@ decode_udp_ip_header(struct interface_info *interface,
unsigned char *upp, *endbuf;
u_int32_t ip_len, ulen, pkt_len;
u_int32_t sum, usum;
- static int ip_packets_seen;
- static int ip_packets_bad_checksum;
- static int udp_packets_seen;
- static int udp_packets_bad_checksum;
- static int udp_packets_length_checked;
- static int udp_packets_length_overflow;
+ static unsigned int ip_packets_seen = 0;
+ static unsigned int ip_packets_bad_checksum = 0;
+ static unsigned int udp_packets_seen = 0;
+ static unsigned int udp_packets_bad_checksum = 0;
+ static unsigned int udp_packets_length_checked = 0;
+ static unsigned int udp_packets_length_overflow = 0;
unsigned len;
/* Designate the end of the input buffer for bounds checks. */
@@ -287,10 +287,10 @@ decode_udp_ip_header(struct interface_info *interface,
udp_packets_length_checked++;
if ((upp + ulen) > endbuf) {
udp_packets_length_overflow++;
- if ((udp_packets_length_checked > 4) &&
- ((udp_packets_length_checked /
- udp_packets_length_overflow) < 2)) {
- log_info("%d udp packets in %d too long - dropped",
+ if (((udp_packets_length_checked > 4) &&
+ (udp_packets_length_overflow != 0)) &&
+ ((udp_packets_length_checked / udp_packets_length_overflow) < 2)) {
+ log_info("%u udp packets in %u too long - dropped",
udp_packets_length_overflow,
udp_packets_length_checked);
udp_packets_length_overflow = 0;
@@ -299,22 +299,31 @@ decode_udp_ip_header(struct interface_info *interface,
return -1;
}
- if ((ulen < sizeof(udp)) || ((upp + ulen) > endbuf))
- return -1;
+ /* If at least 5 with less than 50% bad, start over */
+ if (udp_packets_length_checked > 4) {
+ udp_packets_length_overflow = 0;
+ udp_packets_length_checked = 0;
+ }
/* Check the IP header checksum - it should be zero. */
- ++ip_packets_seen;
+ ip_packets_seen++;
if (wrapsum (checksum (buf + bufix, ip_len, 0))) {
++ip_packets_bad_checksum;
- if (ip_packets_seen > 4 &&
- (ip_packets_seen / ip_packets_bad_checksum) < 2) {
- log_info ("%d bad IP checksums seen in %d packets",
+ if (((ip_packets_seen > 4) && (ip_packets_bad_checksum != 0)) &&
+ ((ip_packets_seen / ip_packets_bad_checksum) < 2)) {
+ log_info ("%u bad IP checksums seen in %u packets",
ip_packets_bad_checksum, ip_packets_seen);
ip_packets_seen = ip_packets_bad_checksum = 0;
}
return -1;
}
+ /* If at least 5 with less than 50% bad, start over */
+ if (ip_packets_seen > 4) {
+ ip_packets_bad_checksum = 0;
+ ip_packets_seen = 0;
+ }
+
/* Copy out the IP source address... */
memcpy(&from->sin_addr, &ip.ip_src, 4);
@@ -339,15 +348,21 @@ decode_udp_ip_header(struct interface_info *interface,
udp_packets_seen++;
if (usum && usum != sum) {
udp_packets_bad_checksum++;
- if (udp_packets_seen > 4 &&
- (udp_packets_seen / udp_packets_bad_checksum) < 2) {
- log_info ("%d bad udp checksums in %d packets",
+ if (((udp_packets_seen > 4) && (udp_packets_bad_checksum != 0)) &&
+ ((udp_packets_seen / udp_packets_bad_checksum) < 2)) {
+ log_info ("%u bad udp checksums in %u packets",
udp_packets_bad_checksum, udp_packets_seen);
udp_packets_seen = udp_packets_bad_checksum = 0;
}
return -1;
}
+ /* If at least 5 with less than 50% bad, start over */
+ if (udp_packets_seen > 4) {
+ udp_packets_bad_checksum = 0;
+ udp_packets_seen = 0;
+ }
+
/* Copy out the port... */
memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
--
2.6.2

View File

@ -6,7 +6,9 @@ SRC_URI += "file://dhcp-3.0.3-dhclient-dbus.patch;striplevel=0 \
file://fixsepbuild.patch \
file://dhclient-script-drop-resolv.conf.dhclient.patch \
file://replace-ifconfig-route.patch \
file://CVE-2015-8605_1.patch \
file://dhcp-xen-checksum.patch \
file://CVE-2015-8605.patch \
"
SRC_URI[md5sum] = "b3a42ece3c7f2cd2e74a3e12ca881d20"