udhcpc: check that 4-byte options are indeed 4-byte, closes 11506
No binary (build failed)
—
(log yok)
| @@ -272,6 +272,15 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) | |
| goto complain; /* complain and return NULL */ | |
| if (optionptr[OPT_CODE] == code) { | |
| + | if (optionptr[OPT_LEN] == 0) { |
| + | /* So far no valid option with length 0 known. |
| + | * Having this check means that searching |
| + | * for DHCP_MESSAGE_TYPE need not worry |
| + | * that returned pointer might be unsafe |
| + | * to dereference. |
| + | */ |
| + | goto complain; /* complain and return NULL */ |
| + | } |
| log_option("option found", optionptr); | |
| return optionptr + OPT_DATA; | |
| } | |
| @@ -289,6 +298,16 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) | |
| return NULL; | |
| } | |
| + | uint8_t* FAST_FUNC udhcp_get_option32(struct dhcp_packet *packet, int code) |
| + | { |
| + | uint8_t *r = udhcp_get_option(packet, code); |
| + | if (r) { |
| + | if (r[-1] != 4) |
| + | r = NULL; |
| + | } |
| + | return r; |
| + | } |
| + | |
| /* Return the position of the 'end' option (no bounds checking) */ | |
| int FAST_FUNC udhcp_end_option(uint8_t *optionptr) | |
| { | |
| @@ -205,6 +205,10 @@ extern const uint8_t dhcp_option_lengths[] ALIGN1; | |
| unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings); | |
| uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; | |
| + | /* Same as above + ensures that option length is 4 bytes |
| + | * (returns NULL if size is different) |
| + | */ |
| + | uint8_t *udhcp_get_option32(struct dhcp_packet *packet, int code) FAST_FUNC; |
| int udhcp_end_option(uint8_t *optionptr) FAST_FUNC; | |
| void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC; | |
| #if ENABLE_UDHCPC || ENABLE_UDHCPD | |
| @@ -1691,7 +1691,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |
| * They say ISC DHCP client supports this case. | |
| */ | |
| server_addr = 0; | |
| - | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); |
| + | temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); |
| if (!temp) { | |
| bb_error_msg("no server ID, using 0.0.0.0"); | |
| } else { | |
| @@ -1718,7 +1718,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |
| struct in_addr temp_addr; | |
| uint8_t *temp; | |
| - | temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); |
| + | temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); |
| if (!temp) { | |
| bb_error_msg("no lease time with ACK, using 1 hour lease"); | |
| lease_seconds = 60 * 60; | |
| @@ -1813,7 +1813,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |
| uint32_t svid; | |
| uint8_t *temp; | |
| - | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); |
| + | temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); |
| if (!temp) { | |
| non_matching_svid: | |
| log1("received DHCP NAK with wrong" | |
| @@ -640,7 +640,7 @@ static void add_server_options(struct dhcp_packet *packet) | |
| static uint32_t select_lease_time(struct dhcp_packet *packet) | |
| { | |
| uint32_t lease_time_sec = server_config.max_lease_sec; | |
| - | uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME); |
| + | uint8_t *lease_time_opt = udhcp_get_option32(packet, DHCP_LEASE_TIME); |
| if (lease_time_opt) { | |
| move_from_unaligned32(lease_time_sec, lease_time_opt); | |
| lease_time_sec = ntohl(lease_time_sec); | |
| @@ -987,7 +987,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| /* Get SERVER_ID if present */ | |
| - | server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); |
| + | server_id_opt = udhcp_get_option32(&packet, DHCP_SERVER_ID); |
| if (server_id_opt) { | |
| uint32_t server_id_network_order; | |
| move_from_unaligned32(server_id_network_order, server_id_opt); | |
| @@ -1011,7 +1011,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |
| } | |
| /* Get REQUESTED_IP if present */ | |
| - | requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); |
| + | requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP); |
| if (requested_ip_opt) { | |
| move_from_unaligned32(requested_nip, requested_ip_opt); | |
| } | |