Project import generated by Copybara. GitOrigin-RevId: df4e2d1bb186010b4919de75d4062f42f6aefa74 Change-Id: Ieedadc9bc46cd6a9d3d439606bafcfd60696b6ff
diff --git a/gdhcp/client.c b/gdhcp/client.c index c50a56d..40139f8 100644 --- a/gdhcp/client.c +++ b/gdhcp/client.c
@@ -1707,12 +1707,12 @@ } #define MINIMUM_LEASE_DURATION 3600 #define MAXIMUM_LEASE_DURATION (30*24*60*60) -static uint32_t get_lease(GDHCPClient *dhcp_client, struct dhcp_packet *packet) +static uint32_t get_lease(GDHCPClient *dhcp_client, struct dhcp_packet *packet, uint16_t packet_len) { uint8_t *option; uint32_t lease_seconds; - option = dhcp_get_option(packet, DHCP_LEASE_TIME); + option = dhcp_get_option(packet, packet_len, DHCP_LEASE_TIME); if (!option) return 3600; @@ -2316,7 +2316,7 @@ } } -static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet) +static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet, uint16_t packet_len) { GDHCPOptionType type; GList *list, *value_list; @@ -2327,7 +2327,7 @@ for (list = dhcp_client->request_list; list; list = list->next) { code = (uint8_t) GPOINTER_TO_INT(list->data); - option = dhcp_get_option(packet, code); + option = dhcp_get_option(packet, packet_len, code); if (!option) { g_hash_table_remove(dhcp_client->code_value_hash, GINT_TO_POINTER((int) code)); @@ -2359,7 +2359,7 @@ { GDHCPClient *dhcp_client = user_data; struct sockaddr_in dst_addr = { 0 }; - struct dhcp_packet packet; + struct dhcp_packet packet = { 0 }; struct dhcpv6_packet *packet6 = NULL; uint8_t *message_type = NULL, *client_id = NULL, *option, *server_id = NULL; @@ -2390,6 +2390,7 @@ re = dhcp_recv_l2_packet(&packet, dhcp_client->listener_sockfd, &dst_addr); + pkt_len = (uint16_t)(unsigned int)re; xid = packet.xid; } else if (dhcp_client->listen_mode == L3) { if (dhcp_client->type == G_DHCP_IPV6) { @@ -2453,7 +2454,7 @@ dhcp_client->status_code = status; } } else { - message_type = dhcp_get_option(&packet, DHCP_MESSAGE_TYPE); + message_type = dhcp_get_option(&packet, pkt_len, DHCP_MESSAGE_TYPE); if (!message_type) return TRUE; } @@ -2492,7 +2493,7 @@ dhcp_client->timeout = 0; dhcp_client->retry_times = 0; - option = dhcp_get_option(&packet, DHCP_SERVER_ID); + option = dhcp_get_option(&packet, pkt_len, DHCP_SERVER_ID); dhcp_client->server_ip = get_be32(option); dhcp_client->requested_ip = ntohl(packet.yiaddr); @@ -2542,9 +2543,9 @@ remove_timeouts(dhcp_client); - dhcp_client->lease_seconds = get_lease(dhcp_client, &packet); + dhcp_client->lease_seconds = get_lease(dhcp_client, &packet, pkt_len); - get_request(dhcp_client, &packet); + get_request(dhcp_client, &packet, pkt_len); switch_listening_mode(dhcp_client, L_NONE); @@ -2552,7 +2553,7 @@ dhcp_client->assigned_ip = get_ip(packet.yiaddr); if (dhcp_client->state == REBOOTING) { - option = dhcp_get_option(&packet, + option = dhcp_get_option(&packet, pkt_len, DHCP_SERVER_ID); dhcp_client->server_ip = get_be32(option); }
diff --git a/gdhcp/common.c b/gdhcp/common.c index bdfc4d9..4c24e66 100644 --- a/gdhcp/common.c +++ b/gdhcp/common.c
@@ -107,18 +107,21 @@ return OPTION_UNKNOWN; } -uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code) +uint8_t *dhcp_get_option(struct dhcp_packet *packet, uint16_t packet_len, int code) { int len, rem; - uint8_t *optionptr; + uint8_t *optionptr, *options_end; + size_t options_len; uint8_t overload = 0; /* option bytes: [code][len][data1][data2]..[dataLEN] */ optionptr = packet->options; rem = sizeof(packet->options); + options_len = packet_len - (sizeof(*packet) - sizeof(packet->options)); + options_end = optionptr + options_len - 1; while (1) { - if (rem <= 0) + if ((rem <= 0) && (optionptr + OPT_CODE > options_end)) /* Bad packet, malformed option field */ return NULL; @@ -149,14 +152,25 @@ break; } + if (optionptr + OPT_LEN > options_end) { + /* bad packet, would read length field from OOB */ + return NULL; + } + len = 2 + optionptr[OPT_LEN]; rem -= len; if (rem < 0) continue; /* complain and return NULL */ - if (optionptr[OPT_CODE] == code) - return optionptr + OPT_DATA; + if (optionptr[OPT_CODE] == code) { + if (optionptr + len > options_end) { + /* bad packet, option length points OOB */ + return NULL; + } else { + return optionptr + OPT_DATA; + } + } if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) overload |= optionptr[OPT_DATA];
diff --git a/gdhcp/common.h b/gdhcp/common.h index 54a8280..f6a44fd 100644 --- a/gdhcp/common.h +++ b/gdhcp/common.h
@@ -170,7 +170,7 @@ [OPTION_U32] = 4, }; -uint8_t *dhcp_get_option(struct dhcp_packet *packet, int code); +uint8_t *dhcp_get_option(struct dhcp_packet *packet, uint16_t packet_len, int code); uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len, int code, uint16_t *option_len, int *option_count); uint8_t *dhcpv6_get_sub_option(unsigned char *option, uint16_t max_len,
diff --git a/gdhcp/server.c b/gdhcp/server.c index 8574c24..280b782 100644 --- a/gdhcp/server.c +++ b/gdhcp/server.c
@@ -416,7 +416,7 @@ } -static uint8_t check_packet_type(struct dhcp_packet *packet) +static uint8_t check_packet_type(struct dhcp_packet *packet, uint16_t packet_len) { uint8_t *type; @@ -426,7 +426,7 @@ if (packet->op != BOOTREQUEST) return 0; - type = dhcp_get_option(packet, DHCP_MESSAGE_TYPE); + type = dhcp_get_option(packet, packet_len, DHCP_MESSAGE_TYPE); if (!type) return 0; @@ -651,6 +651,7 @@ struct dhcp_lease *lease; uint32_t requested_nip = 0; uint8_t type, *server_id_option, *request_ip_option; + uint16_t packet_len; int re; if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { @@ -661,12 +662,13 @@ re = dhcp_recv_l3_packet(&packet, dhcp_server->listener_sockfd); if (re < 0) return TRUE; + packet_len = (uint16_t)(unsigned int)re; - type = check_packet_type(&packet); + type = check_packet_type(&packet, packet_len); if (type == 0) return TRUE; - server_id_option = dhcp_get_option(&packet, DHCP_SERVER_ID); + server_id_option = dhcp_get_option(&packet, packet_len, DHCP_SERVER_ID); if (server_id_option) { uint32_t server_nid = get_unaligned((const uint32_t *) server_id_option); @@ -675,7 +677,7 @@ return TRUE; } - request_ip_option = dhcp_get_option(&packet, DHCP_REQUESTED_IP); + request_ip_option = dhcp_get_option(&packet, packet_len, DHCP_REQUESTED_IP); if (request_ip_option) requested_nip = get_be32(request_ip_option);
diff --git a/src/dnsproxy.c b/src/dnsproxy.c index fbd4ccf..e27a306 100644 --- a/src/dnsproxy.c +++ b/src/dnsproxy.c
@@ -1813,6 +1813,7 @@ char **uncompressed_ptr) { char *uptr = *uncompressed_ptr; /* position in result buffer */ + char * const uncomp_end = uncompressed + uncomp_len - 1; DBG("count %d ptr %p end %p uptr %p", field_count, ptr, end, uptr); @@ -1833,12 +1834,15 @@ * tmp buffer. */ - ulen = strlen(name); - strncpy(uptr, name, uncomp_len - (uptr - uncompressed)); - DBG("pos %d ulen %d left %d name %s", pos, ulen, (int)(uncomp_len - (uptr - uncompressed)), uptr); + ulen = strlen(name); + if ((uptr + ulen + 1) > uncomp_end) { + goto out; + } + strncpy(uptr, name, uncomp_len - (uptr - uncompressed)); + uptr += ulen; *uptr++ = '\0'; @@ -1848,6 +1852,10 @@ * We copy also the fixed portion of the result (type, class, * ttl, address length and the address) */ + if ((uptr + NS_RRFIXEDSZ) > uncomp_end) { + DBG("uncompressed data too large for buffer"); + goto out; + } memcpy(uptr, ptr, NS_RRFIXEDSZ); dns_type = uptr[0] << 8 | uptr[1];