NULL);
}
-static uint32_t get_lease(struct dhcp_packet *packet)
+static uint32_t get_lease(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;
}
}
-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;
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));
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) {
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;
}
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);
remove_timeouts(dhcp_client);
- dhcp_client->lease_seconds = get_lease(&packet);
+ dhcp_client->lease_seconds = get_lease(&packet, pkt_len);
#if defined TIZEN_EXT
dhcp_client->dhcp_lease_seconds = dhcp_client->lease_seconds;
#endif
- get_request(dhcp_client, &packet);
+ get_request(dhcp_client, &packet, pkt_len);
switch_listening_mode(dhcp_client, L_NONE);
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);
}
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;
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];
};
#endif
-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,
}
-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;
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;
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)) {
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);
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);