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).
This commit is contained in:
Johan Hedberg 2011-10-14 14:23:05 +03:00
parent 9122bd7ec7
commit 6ecbffae1d

View File

@ -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);
}