OSDN Git Service

Fix leaks and buffer overflows in EIR parsing
authorJohan Hedberg <johan.hedberg@intel.com>
Fri, 14 Oct 2011 08:15:14 +0000 (11:15 +0300)
committerJohan Hedberg <johan.hedberg@intel.com>
Fri, 14 Oct 2011 08:15:14 +0000 (11:15 +0300)
By calling g_utf8_validate and allocating eir->name inside the parsing
loop the code was exposing itself to buffer overflows and memory leaks.
This is because the check for incorrect length fields is only done after
exiting the loop (if (len > HCI_MAX_EIR_LENGTH)). By only setting a
pointer to the name and doing the processing after checking the length
validity both issues can be avoided.

src/eir.c

index d632fa8..8772191 100644 (file)
--- a/src/eir.c
+++ b/src/eir.c
@@ -68,6 +68,8 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data)
        uint8_t *uuid128 = NULL;
        uuid_t service;
        char *uuid_str;
+       const char *name = NULL;
+       size_t name_len;
        unsigned int i;
 
        eir->flags = -1;
@@ -104,12 +106,8 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data)
                        break;
                case EIR_NAME_SHORT:
                case EIR_NAME_COMPLETE:
-                       if (g_utf8_validate((char *) &eir_data[2],
-                                                       field_len - 1, NULL))
-                               eir->name = g_strndup((char *) &eir_data[2],
-                                                               field_len - 1);
-                       else
-                               eir->name = g_strdup("");
+                       name = (const char *) &eir_data[2];
+                       name_len = field_len - 1;
                        eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
                        break;
                }
@@ -122,6 +120,13 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data)
        if (len > HCI_MAX_EIR_LENGTH)
                return -EINVAL;
 
+       if (name != NULL) {
+               if (g_utf8_validate(name, name_len, NULL))
+                       eir->name = g_strndup(name, name_len);
+               else
+                       eir->name = g_strdup("");
+       }
+
        total = uuid16_count + uuid32_count + uuid128_count;
 
        /* No UUIDs were parsed, so skip code below */