diff --git a/RELNOTES b/RELNOTES index 3b25d6a9..85ed82c6 100644 --- a/RELNOTES +++ b/RELNOTES @@ -77,6 +77,19 @@ work on other platforms. Please report any problems and suggested fixes to a lease file. Thanks to Marius Tomaschewski from SUSE for the report and prototype patch for this ticket as well as ticket 27289. +! Previously the server code was relaxed to allow packets with zero + length client ids to be processed. Under some situations use of + zero length client ids can cause the server to go into an infinite + loop. As such ids are not valid according to RFC 2132 section 9.14 + the server no longer accepts them. Client ids with a length of 1 + are also invalid but the server still accepts them in order to + minimize disruption. The restriction will likely be tightened in + the future to disallow ids with a length of 1. + Thanks to Markus Hietava of Codenomicon CROSS project for the + finding this issue and CERT-FI for vulnerability coordination. + [ISC-Bugs #29851] + CVE: CVE-2012-3571 + Changes since 4.2.3 ! Add a check for a null pointer before calling the regexec function. diff --git a/common/options.c b/common/options.c index ce2c08ae..56d2e88e 100644 --- a/common/options.c +++ b/common/options.c @@ -3798,11 +3798,13 @@ void do_packet (interface, packet, len, from_port, from, hfrom) data_string_forget (&dp, MDL); } } - - if (decoded_packet -> packet_type) - dhcp (decoded_packet); - else - bootp (decoded_packet); + + if (validate_packet(decoded_packet) != 0) { + if (decoded_packet->packet_type) + dhcp(decoded_packet); + else + bootp(decoded_packet); + } /* If the caller kept the packet, they'll have upped the refcnt. */ packet_dereference (&decoded_packet, MDL); @@ -4122,4 +4124,47 @@ add_option(struct option_state *options, return 1; } +/** + * Checks if received BOOTP/DHCPv4 packet is sane + * + * @param packet received, decoded packet + * + * @return 1 if packet is sane, 0 if it is not + */ +int validate_packet(struct packet *packet) +{ + struct option_cache *oc = NULL; + oc = lookup_option (&dhcp_universe, packet->options, + DHO_DHCP_CLIENT_IDENTIFIER); + if (oc) { + /* Let's check if client-identifier is sane */ + if (oc->data.len == 0) { + log_debug("Dropped DHCPv4 packet with zero-length client-id"); + return (0); + + } else if (oc->data.len == 1) { + /* + * RFC2132, section 9.14 states that minimum length of client-id + * is 2. We will allow single-character client-ids for now (for + * backwards compatibility), but warn the user that support for + * this is against the standard. + */ + log_debug("Accepted DHCPv4 packet with one-character client-id - " + "a future version of ISC DHCP will reject this"); + } + } else { + /* + * If hlen is 0 we don't have any identifier, we warn the user + * but continue processing the packet as we can. + */ + if (packet->raw->hlen == 0) { + log_debug("Received DHCPv4 packet without client-id" + " option and empty hlen field."); + } + } + + /* @todo: Add checks for other received options */ + + return (1); +} diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 98ba0751..6aaa6ed0 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -1835,6 +1835,8 @@ void do_packet6(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t); int packet6_len_okay(const char *, int); +int validate_packet(struct packet *); + int add_option(struct option_state *options, unsigned int option_num, void *data,