HS 2.0: Clarify OSU Provider list length validation
authorJouni Malinen <j@w1.fi>
Thu, 4 Dec 2014 22:56:05 +0000 (00:56 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 4 Dec 2014 22:56:05 +0000 (00:56 +0200)
The previous version was somewhat too complex for some static analyzers.
Use local variables for the extracted length fields and explicitly
compare these against the remaining buffer length. (CID 68121)

Signed-off-by: Jouni Malinen <j@w1.fi>
wpa_supplicant/hs20_supplicant.c

index 315fa28..d91a936 100644 (file)
@@ -562,7 +562,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        const u8 *end = pos + len;
        u16 len2;
        const u8 *pos2;
-       u8 uri_len;
+       u8 uri_len, osu_method_len, osu_nai_len;
 
        wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len);
        prov = os_realloc_array(wpa_s->osu_prov,
@@ -586,7 +586,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        }
        len2 = WPA_GET_LE16(pos);
        pos += 2;
-       if (pos + len2 > end) {
+       if (len2 > end - pos) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
                           "Friendly Name Duples");
                return;
@@ -623,13 +623,19 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        pos += uri_len;
 
        /* OSU Method list */
-       if (pos + 1 > end || pos + 1 + pos[0] > end) {
+       if (pos + 1 > end) {
+               wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
+                          "list length");
+               return;
+       }
+       osu_method_len = pos[0];
+       if (osu_method_len > end - pos - 1) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
                           "list");
                return;
        }
        pos2 = pos + 1;
-       pos += 1 + pos[0];
+       pos += 1 + osu_method_len;
        while (pos2 < pos) {
                if (*pos2 < 32)
                        prov->osu_methods |= BIT(*pos2);
@@ -644,7 +650,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        }
        len2 = WPA_GET_LE16(pos);
        pos += 2;
-       if (pos + len2 > end) {
+       if (len2 > end - pos) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
                           "Available");
                return;
@@ -655,6 +661,8 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        /* Icons Available */
        while (pos2 < pos) {
                struct osu_icon *icon = &prov->icon[prov->icon_count];
+               u8 flen;
+
                if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
                        break;
@@ -667,31 +675,43 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                os_memcpy(icon->lang, pos2, 3);
                pos2 += 3;
 
-               if (pos2 + 1 + pos2[0] > pos) {
+               flen = pos2[0];
+               if (flen > pos - pos2 - 1) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
                        break;
                }
-               os_memcpy(icon->icon_type, pos2 + 1, pos2[0]);
-               pos2 += 1 + pos2[0];
+               os_memcpy(icon->icon_type, pos2 + 1, flen);
+               pos2 += 1 + flen;
 
-               if (pos2 + 1 + pos2[0] > pos) {
+               if (pos2 + 1 > pos) {
+                       wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
+                                  "Filename length");
+                       break;
+               }
+               flen = pos2[0];
+               if (flen > pos - pos2 - 1) {
                        wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
                                   "Filename");
                        break;
                }
-               os_memcpy(icon->filename, pos2 + 1, pos2[0]);
-               pos2 += 1 + pos2[0];
+               os_memcpy(icon->filename, pos2 + 1, flen);
+               pos2 += 1 + flen;
 
                prov->icon_count++;
        }
 
        /* OSU_NAI */
-       if (pos + 1 > end || pos + 1 + pos[0] > end) {
+       if (pos + 1 > end) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
                return;
        }
-       os_memcpy(prov->osu_nai, pos + 1, pos[0]);
-       pos += 1 + pos[0];
+       osu_nai_len = pos[0];
+       if (osu_nai_len > end - pos - 1) {
+               wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
+               return;
+       }
+       os_memcpy(prov->osu_nai, pos + 1, osu_nai_len);
+       pos += 1 + osu_nai_len;
 
        /* OSU Service Description Length */
        if (pos + 2 > end) {
@@ -701,7 +721,7 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        }
        len2 = WPA_GET_LE16(pos);
        pos += 2;
-       if (pos + len2 > end) {
+       if (len2 > end - pos) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
                           "Service Description Duples");
                return;
@@ -712,15 +732,18 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        /* OSU Service Description Duples */
        while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) {
                struct osu_lang_string *f;
-               if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
+               u8 descr_len;
+
+               descr_len = pos2[0];
+               if (descr_len > pos - pos2 - 1 || descr_len < 3) {
                        wpa_printf(MSG_DEBUG, "Invalid OSU Service "
                                   "Description");
                        break;
                }
                f = &prov->serv_desc[prov->serv_desc_count++];
                os_memcpy(f->lang, pos2 + 1, 3);
-               os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
-               pos2 += 1 + pos2[0];
+               os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3);
+               pos2 += 1 + descr_len;
        }
 
        wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,