From: Roy Marples Date: Sat, 28 Feb 2009 09:00:40 +0000 (+0000) Subject: Backport UDP validation from trunk X-Git-Tag: v4.0.13~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8df4b32f928dc8ce7c091645987089700f6e5d61;p=thirdparty%2Fdhcpcd.git Backport UDP validation from trunk --- diff --git a/client.c b/client.c index d14bd751..e9645662 100644 --- a/client.c +++ b/client.c @@ -1548,7 +1548,7 @@ handle_dhcp_packet(struct if_state *state, const struct options *options) } if (bytes == -1) break; - if (valid_udp_packet(packet) == -1) + if (valid_udp_packet(packet, bytes) == -1) continue; bytes = get_udp_data(&pp, packet); if ((size_t)bytes > sizeof(*dhcp)) { diff --git a/net.c b/net.c index fa5af103..29344f82 100644 --- a/net.c +++ b/net.c @@ -634,44 +634,42 @@ get_udp_data(const uint8_t **data, const uint8_t *udp) } int -valid_udp_packet(const uint8_t *data) +valid_udp_packet(const uint8_t *data, size_t data_len) { struct udp_dhcp_packet packet; - uint16_t bytes; - uint16_t ipsum; - uint16_t iplen; - uint16_t udpsum; - struct in_addr source; - struct in_addr dest; - int retval = 0; - - memcpy(&packet, data, sizeof(packet)); - bytes = ntohs(packet.ip.ip_len); - ipsum = packet.ip.ip_sum; - iplen = packet.ip.ip_len; - udpsum = packet.udp.uh_sum; + uint16_t bytes, udpsum; - if (0 != checksum(&packet.ip, sizeof(packet.ip))) { + if (data_len > sizeof(packet)) { + errno = EINVAL; + return -1; + } + memcpy(&packet, data, data_len); + if (checksum(&packet.ip, sizeof(packet.ip)) != 0) { errno = EINVAL; return -1; } - packet.ip.ip_sum = 0; - memcpy(&source, &packet.ip.ip_src, sizeof(packet.ip.ip_src)); - memcpy(&dest, &packet.ip.ip_dst, sizeof(packet.ip.ip_dst)); - memset(&packet.ip, 0, sizeof(packet.ip)); + bytes = ntohs(packet.ip.ip_len); + if (data_len < bytes) { + errno = EINVAL; + return -1; + } + udpsum = packet.udp.uh_sum; packet.udp.uh_sum = 0; - - packet.ip.ip_p = IPPROTO_UDP; - memcpy(&packet.ip.ip_src, &source, sizeof(packet.ip.ip_src)); - memcpy(&packet.ip.ip_dst, &dest, sizeof(packet.ip.ip_dst)); + packet.ip.ip_hl = 0; + packet.ip.ip_v = 0; + packet.ip.ip_tos = 0; packet.ip.ip_len = packet.udp.uh_ulen; - if (udpsum && udpsum != checksum(&packet, bytes)) { + packet.ip.ip_id = 0; + packet.ip.ip_off = 0; + packet.ip.ip_ttl = 0; + packet.ip.ip_sum = 0; + if (udpsum && checksum(&packet, bytes) != udpsum) { errno = EINVAL; - retval = -1; + return -1; } - return retval; + return 0; } int diff --git a/net.h b/net.h index e9005d02..1447aba0 100644 --- a/net.h +++ b/net.h @@ -160,7 +160,7 @@ const size_t udp_dhcp_len; ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t, struct in_addr, struct in_addr); ssize_t get_udp_data(const uint8_t **, const uint8_t *); -int valid_udp_packet(const uint8_t *); +int valid_udp_packet(const uint8_t *, size_t); int open_socket(struct interface *, int); ssize_t send_packet(const struct interface *, struct in_addr,