Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 1 | Solves CVE-2015-8605 that caused DoS when an invalid lenght field in IPv4 UDP |
| 2 | was recived by the server. |
| 3 | |
| 4 | Upstream-Status: Backport |
| 5 | CVE: CVE-2015-8605 |
| 6 | |
| 7 | Signed-off-by: Mariano Lopez <mariano.lopez@linux.intel.com> |
| 8 | |
| 9 | ======================================================================= |
| 10 | diff --git a/common/packet.c b/common/packet.c |
| 11 | index b530432..e600e37 100644 |
| 12 | --- a/common/packet.c |
| 13 | +++ b/common/packet.c |
| 14 | @@ -220,7 +220,28 @@ ssize_t decode_hw_header (interface, buf, bufix, from) |
| 15 | } |
| 16 | } |
| 17 | |
| 18 | -/* UDP header and IP header decoded together for convenience. */ |
| 19 | +/*! |
| 20 | + * |
| 21 | + * \brief UDP header and IP header decoded together for convenience. |
| 22 | + * |
| 23 | + * Attempt to decode the UDP and IP headers and, if necessary, checksum |
| 24 | + * the packet. |
| 25 | + * |
| 26 | + * \param inteface - the interface on which the packet was recevied |
| 27 | + * \param buf - a pointer to the buffer for the received packet |
| 28 | + * \param bufix - where to start processing the buffer, previous |
| 29 | + * routines may have processed parts of the buffer already |
| 30 | + * \param from - space to return the address of the packet sender |
| 31 | + * \param buflen - remaining length of the buffer, this will have been |
| 32 | + * decremented by bufix by the caller |
| 33 | + * \param rbuflen - space to return the length of the payload from the udp |
| 34 | + * header |
| 35 | + * \param csum_ready - indication if the checksum is valid for use |
| 36 | + * non-zero indicates the checksum should be validated |
| 37 | + * |
| 38 | + * \return - the index to the first byte of the udp payload (that is the |
| 39 | + * start of the DHCP packet |
| 40 | + */ |
| 41 | |
| 42 | ssize_t |
| 43 | decode_udp_ip_header(struct interface_info *interface, |
| 44 | @@ -231,7 +252,7 @@ decode_udp_ip_header(struct interface_info *interface, |
| 45 | unsigned char *data; |
| 46 | struct ip ip; |
| 47 | struct udphdr udp; |
| 48 | - unsigned char *upp, *endbuf; |
| 49 | + unsigned char *upp; |
| 50 | u_int32_t ip_len, ulen, pkt_len; |
| 51 | static unsigned int ip_packets_seen = 0; |
| 52 | static unsigned int ip_packets_bad_checksum = 0; |
| 53 | @@ -241,11 +262,8 @@ decode_udp_ip_header(struct interface_info *interface, |
| 54 | static unsigned int udp_packets_length_overflow = 0; |
| 55 | unsigned len; |
| 56 | |
| 57 | - /* Designate the end of the input buffer for bounds checks. */ |
| 58 | - endbuf = buf + bufix + buflen; |
| 59 | - |
| 60 | /* Assure there is at least an IP header there. */ |
| 61 | - if ((buf + bufix + sizeof(ip)) > endbuf) |
| 62 | + if (sizeof(ip) > buflen) |
| 63 | return -1; |
| 64 | |
| 65 | /* Copy the IP header into a stack aligned structure for inspection. |
| 66 | @@ -257,13 +275,17 @@ decode_udp_ip_header(struct interface_info *interface, |
| 67 | ip_len = (*upp & 0x0f) << 2; |
| 68 | upp += ip_len; |
| 69 | |
| 70 | - /* Check the IP packet length. */ |
| 71 | + /* Check packet lengths are within the buffer: |
| 72 | + * first the ip header (ip_len) |
| 73 | + * then the packet length from the ip header (pkt_len) |
| 74 | + * then the udp header (ip_len + sizeof(udp) |
| 75 | + * We are liberal in what we accept, the udp payload should fit within |
| 76 | + * pkt_len, but we only check against the full buffer size. |
| 77 | + */ |
| 78 | pkt_len = ntohs(ip.ip_len); |
| 79 | - if (pkt_len > buflen) |
| 80 | - return -1; |
| 81 | - |
| 82 | - /* Assure after ip_len bytes that there is enough room for a UDP header. */ |
| 83 | - if ((upp + sizeof(udp)) > endbuf) |
| 84 | + if ((ip_len > buflen) || |
| 85 | + (pkt_len > buflen) || |
| 86 | + ((ip_len + sizeof(udp)) > buflen)) |
| 87 | return -1; |
| 88 | |
| 89 | /* Copy the UDP header into a stack aligned structure for inspection. */ |
| 90 | @@ -284,7 +306,8 @@ decode_udp_ip_header(struct interface_info *interface, |
| 91 | return -1; |
| 92 | |
| 93 | udp_packets_length_checked++; |
| 94 | - if ((upp + ulen) > endbuf) { |
| 95 | + /* verify that the payload length from the udp packet fits in the buffer */ |
| 96 | + if ((ip_len + ulen) > buflen) { |
| 97 | udp_packets_length_overflow++; |
| 98 | if (((udp_packets_length_checked > 4) && |
| 99 | (udp_packets_length_overflow != 0)) && |