summaryrefslogtreecommitdiff
path: root/tools/hcitool.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2011-10-14 14:23:05 +0300
committerJohan Hedberg <johan.hedberg@intel.com>2011-10-14 14:23:05 +0300
commit6ecbffae1d0ee5b6e656dc9e9db3f8b86c0dbe1f (patch)
tree977152d218c04c310d260906db0d34157b8415a4 /tools/hcitool.c
parent9122bd7ec7df653cbf7443282636693470b73f89 (diff)
downloadbluez-6ecbffae1d0ee5b6e656dc9e9db3f8b86c0dbe1f.tar.gz
hcitool: Fix EIR parsing
There were missing buffer size checks and wrong assumptions about the EIR data length (core spec 4.0 defines it to be max 31 bytes, so the name can be max 29 bytes).
Diffstat (limited to 'tools/hcitool.c')
-rw-r--r--tools/hcitool.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/tools/hcitool.c b/tools/hcitool.c
index 3547794ae..5c4a0bc31 100644
--- a/tools/hcitool.c
+++ b/tools/hcitool.c
@@ -2308,7 +2308,7 @@ static void cmd_clock(int dev_id, int argc, char **argv)
static int read_flags(uint8_t *flags, const uint8_t *data, size_t size)
{
- unsigned int offset;
+ size_t offset;
if (!flags || !data)
return -EINVAL;
@@ -2316,12 +2316,17 @@ static int read_flags(uint8_t *flags, const uint8_t *data, size_t size)
offset = 0;
while (offset < size) {
uint8_t len = data[offset];
- uint8_t type = data[offset + 1];
+ uint8_t type;
/* Check if it is the end of the significant part */
if (len == 0)
break;
+ if (len + offset > size)
+ break;
+
+ type = data[offset + 1];
+
if (type == FLAGS_AD_TYPE) {
*flags = data[offset + 2];
return 0;
@@ -2366,38 +2371,40 @@ static void sigint_handler(int sig)
signal_received = sig;
}
-static void eir_parse_name(uint8_t *eir_data, char *name)
+static void eir_parse_name(uint8_t *eir, size_t eir_len,
+ char *buf, size_t buf_len)
{
- int len;
+ size_t offset;
- if (eir_data == NULL)
- goto failed;
-
- len = 0;
- while (len < HCI_MAX_EIR_LENGTH - 1) {
- uint8_t field_len = eir_data[0];
+ offset = 0;
+ while (offset < eir_len) {
+ uint8_t field_len = eir[0];
+ size_t name_len;
/* Check for the end of EIR */
if (field_len == 0)
break;
- switch (eir_data[1]) {
+ if (offset + field_len > eir_len)
+ goto failed;
+
+ switch (eir[1]) {
case EIR_NAME_SHORT:
case EIR_NAME_COMPLETE:
- if (field_len > HCI_MAX_NAME_LENGTH)
+ name_len = field_len - 1;
+ if (name_len > buf_len)
goto failed;
- memcpy(name, &eir_data[2], field_len - 1);
+ memcpy(buf, &eir[2], name_len);
return;
}
- len += field_len + 1;
- eir_data += field_len + 1;
+ offset += field_len + 1;
+ eir += field_len + 1;
}
failed:
- sprintf(name, "(unknown)");
- return;
+ snprintf(buf, buf_len, "(unknown)");
}
static int print_advertising_devices(int dd, uint8_t filter_type)
@@ -2455,12 +2462,13 @@ static int print_advertising_devices(int dd, uint8_t filter_type)
/* Ignoring multiple reports */
info = (le_advertising_info *) (meta->data + 1);
if (check_report_filter(filter_type, info)) {
- char name[HCI_MAX_NAME_LENGTH + 1];
+ char name[30];
memset(name, 0, sizeof(name));
ba2str(&info->bdaddr, addr);
- eir_parse_name(info->data, name);
+ eir_parse_name(info->data, info->length,
+ name, sizeof(name) - 1);
printf("%s %s\n", addr, name);
}