Bluetooth: Check buffer length in GATT rsp functions
Add length checks local to the parsing function. This removes the need
for a separate data validation step.
Signed-off-by: Aleksander Wasaznik <aleksander.wasaznik@nordicsemi.no>
(cherry picked from commit 3eeb8f8d18d02962e0a842e46ad247648f84fa41)
diff --git a/subsys/bluetooth/host/gatt.c b/subsys/bluetooth/host/gatt.c
index 69d43de..6744d77 100644
--- a/subsys/bluetooth/host/gatt.c
+++ b/subsys/bluetooth/host/gatt.c
@@ -3910,7 +3910,7 @@
struct bt_gatt_discover_params *params,
uint16_t length)
{
- const struct bt_att_read_type_rsp *rsp = pdu;
+ const struct bt_att_read_type_rsp *rsp;
uint16_t handle = 0U;
struct bt_gatt_include value;
union {
@@ -3919,6 +3919,13 @@
struct bt_uuid_128 u128;
} u;
+ if (length < sizeof(*rsp)) {
+ LOG_WRN("Parse err");
+ goto done;
+ }
+
+ rsp = pdu;
+
/* Data can be either in UUID16 or UUID128 */
switch (rsp->len) {
case 8: /* UUID16 */
@@ -4003,7 +4010,7 @@
struct bt_gatt_discover_params *params,
uint16_t length)
{
- const struct bt_att_read_type_rsp *rsp = pdu;
+ const struct bt_att_read_type_rsp *rsp;
uint16_t handle = 0U;
union {
struct bt_uuid uuid;
@@ -4011,6 +4018,13 @@
struct bt_uuid_128 u128;
} u;
+ if (length < sizeof(*rsp)) {
+ LOG_WRN("Parse err");
+ goto done;
+ }
+
+ rsp = pdu;
+
/* Data can be either in UUID16 or UUID128 */
switch (rsp->len) {
case 7: /* UUID16 */
@@ -4084,7 +4098,7 @@
struct bt_gatt_discover_params *params,
uint16_t length)
{
- const struct bt_att_read_type_rsp *rsp = pdu;
+ const struct bt_att_read_type_rsp *rsp;
uint16_t handle = 0U;
uint16_t uuid_val;
@@ -4094,6 +4108,13 @@
uuid_val = BT_UUID_16(params->uuid)->val;
+ if (length < sizeof(*rsp)) {
+ LOG_WRN("Parse err");
+ goto done;
+ }
+
+ rsp = pdu;
+
/* Parse characteristics found */
for (length--, pdu = rsp->data; length >= rsp->len;
length -= rsp->len, pdu = (const uint8_t *)pdu + rsp->len) {
@@ -4103,9 +4124,16 @@
struct bt_gatt_cep cep;
struct bt_gatt_scc scc;
} value;
- const struct bt_att_data *data = pdu;
+ const struct bt_att_data *data;
struct bt_gatt_attr attr;
+ if (length < sizeof(*data)) {
+ LOG_WRN("Parse err dat");
+ goto done;
+ }
+
+ data = pdu;
+
handle = sys_le16_to_cpu(data->handle);
/* Handle 0 is invalid */
if (!handle) {
@@ -4114,17 +4142,39 @@
switch (uuid_val) {
case BT_UUID_GATT_CEP_VAL:
+ if (length < sizeof(*data) + sizeof(uint16_t)) {
+ LOG_WRN("Parse err cep");
+ goto done;
+ }
+
value.cep.properties = sys_get_le16(data->value);
break;
case BT_UUID_GATT_CCC_VAL:
+ if (length < sizeof(*data) + sizeof(uint16_t)) {
+ LOG_WRN("Parse err ccc");
+ goto done;
+ }
+
value.ccc.flags = sys_get_le16(data->value);
break;
case BT_UUID_GATT_SCC_VAL:
+ if (length < sizeof(*data) + sizeof(uint16_t)) {
+ LOG_WRN("Parse err scc");
+ goto done;
+ }
+
value.scc.flags = sys_get_le16(data->value);
break;
case BT_UUID_GATT_CPF_VAL:
{
- struct gatt_cpf *cpf = (struct gatt_cpf *)data->value;
+ struct gatt_cpf *cpf;
+
+ if (length < sizeof(*data) + sizeof(*cpf)) {
+ LOG_WRN("Parse err cpf");
+ goto done;
+ }
+
+ cpf = (void *)data->value;
value.cpf.format = cpf->format;
value.cpf.exponent = cpf->exponent;
@@ -4227,7 +4277,7 @@
struct bt_gatt_discover_params *params,
uint16_t length)
{
- const struct bt_att_read_group_rsp *rsp = pdu;
+ const struct bt_att_read_group_rsp *rsp;
uint16_t start_handle, end_handle = 0U;
union {
struct bt_uuid uuid;
@@ -4235,6 +4285,13 @@
struct bt_uuid_128 u128;
} u;
+ if (length < sizeof(*rsp)) {
+ LOG_WRN("Parse err");
+ goto done;
+ }
+
+ rsp = pdu;
+
/* Data can be either in UUID16 or UUID128 */
switch (rsp->len) {
case 6: /* UUID16 */
@@ -4365,7 +4422,7 @@
const void *pdu, uint16_t length,
void *user_data)
{
- const struct bt_att_find_info_rsp *rsp = pdu;
+ const struct bt_att_find_info_rsp *rsp;
struct bt_gatt_discover_params *params = user_data;
uint16_t handle = 0U;
uint16_t len;
@@ -4387,6 +4444,13 @@
goto done;
}
+ if (length < sizeof(*rsp)) {
+ LOG_WRN("Parse err");
+ goto done;
+ }
+
+ rsp = pdu;
+
/* Data can be either in UUID16 or UUID128 */
switch (rsp->format) {
case BT_ATT_INFO_16:
@@ -4992,7 +5056,7 @@
void *user_data)
{
struct bt_gatt_write_params *params = user_data;
- const struct bt_att_prepare_write_rsp *rsp = pdu;
+ const struct bt_att_prepare_write_rsp *rsp;
size_t len;
bool data_valid;
@@ -5004,6 +5068,13 @@
return;
}
+ if (length < sizeof(*rsp)) {
+ LOG_WRN("Parse err");
+ goto fail;
+ }
+
+ rsp = pdu;
+
len = length - sizeof(*rsp);
if (len > params->length) {
LOG_ERR("Incorrect length, canceling write");