udhcpc: check read of option length byte to be within packet
authorBrian Foley <bpfoley@google.com>
Tue, 25 Oct 2016 12:20:55 +0000 (14:20 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 25 Oct 2016 12:20:55 +0000 (14:20 +0200)
function                                             old     new   delta
udhcp_get_option                                     215     220      +5
udhcp_run_script                                     802     803      +1

Signed-off-by: Brian Foley <bpfoley@google.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/udhcp/common.c
networking/udhcp/dhcpc.c

index 0cf4dab63c559c4d1ad718d2172cfc7780e166a9..589bcd674986cb84aae26fbb112c18168b21be12 100644 (file)
@@ -226,9 +226,12 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
        rem = sizeof(packet->options);
        while (1) {
                if (rem <= 0) {
+ complain:
                        bb_error_msg("bad packet, malformed option field");
                        return NULL;
                }
+
+               /* DHCP_PADDING and DHCP_END have no [len] byte */
                if (optionptr[OPT_CODE] == DHCP_PADDING) {
                        rem--;
                        optionptr++;
@@ -251,10 +254,13 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
                        }
                        break;
                }
+
+               if (rem <= OPT_LEN)
+                       goto complain; /* complain and return NULL */
                len = 2 + optionptr[OPT_LEN];
                rem -= len;
                if (rem < 0)
-                       continue; /* complain and return NULL */
+                       goto complain; /* complain and return NULL */
 
                if (optionptr[OPT_CODE] == code) {
                        log_option("option found", optionptr);
index bef73277ae49b7a734a22fdd4eff742451f93955..1c1051107ac6aaf8a941528685c7dea247548013 100644 (file)
@@ -450,7 +450,7 @@ static char **fill_envp(struct dhcp_packet *packet)
                        temp = udhcp_get_option(packet, i);
                        if (temp) {
                                if (i == DHCP_OPTION_OVERLOAD)
-                                       overload = *temp;
+                                       overload |= *temp;
                                else if (i == DHCP_SUBNET)
                                        envc++; /* for $mask */
                                envc++;
@@ -476,7 +476,7 @@ static char **fill_envp(struct dhcp_packet *packet)
         * uint16_t secs;   // elapsed since client began acquisition/renewal
         * uint16_t flags;  // only one flag so far: bcast. Never set by server
         * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different
-        *                  // if during renew server wants to give us differn IP?)
+        *                  // if during renew server wants to give us different IP?)
         * uint32_t gateway_nip; // relay agent IP address
         * uint8_t chaddr[16]; // link-layer client hardware address (MAC)
         * TODO: export gateway_nip as $giaddr?