Skip to content

Commit c4585ed

Browse files
GustavoARSilvaVudentz
authored andcommitted
Bluetooth: hci_conn, hci_sync: Use __counted_by() to avoid -Wfamnae warnings
Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). Also, -Wflex-array-member-not-at-end is coming in GCC-14, and we are getting ready to enable it globally. So, use the `DEFINE_FLEX()` helper for multiple on-stack definitions of a flexible structure where the size of the flexible-array member is known at compile-time, and refactor the rest of the code, accordingly. Notice that, due to the use of `__counted_by()` in `struct hci_cp_le_create_cis`, the for loop in function `hci_cs_le_create_cis()` had to be modified. Once the index `i`, through which `cp->cis[i]` is accessed, falls in the interval [0, cp->num_cis), `cp->num_cis` cannot be decremented all the way down to zero while accessing `cp->cis[]`: net/bluetooth/hci_event.c:4310: 4310 for (i = 0; cp->num_cis; cp->num_cis--, i++) { ... 4314 handle = __le16_to_cpu(cp->cis[i].cis_handle); otherwise, only half (one iteration before `cp->num_cis == i`) or half plus one (one iteration before `cp->num_cis < i`) of the items in the array will be accessed before running into an out-of-bounds issue. So, in order to avoid this, set `cp->num_cis` to zero just after the for loop. Also, make use of `aux_num_cis` variable to update `cmd->num_cis` after a `list_for_each_entry_rcu()` loop. With these changes, fix the following warnings: net/bluetooth/hci_sync.c:1239:56: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] net/bluetooth/hci_sync.c:1415:51: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] net/bluetooth/hci_sync.c:1731:51: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] net/bluetooth/hci_sync.c:6497:45: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end] Link: KSPP#202 Signed-off-by: Gustavo A. R. Silva <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 3487cda commit c4585ed

File tree

3 files changed

+40
-55
lines changed

3 files changed

+40
-55
lines changed

include/net/bluetooth/hci.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,7 +2026,7 @@ struct hci_cp_le_set_ext_adv_data {
20262026
__u8 operation;
20272027
__u8 frag_pref;
20282028
__u8 length;
2029-
__u8 data[];
2029+
__u8 data[] __counted_by(length);
20302030
} __packed;
20312031

20322032
#define HCI_OP_LE_SET_EXT_SCAN_RSP_DATA 0x2038
@@ -2035,7 +2035,7 @@ struct hci_cp_le_set_ext_scan_rsp_data {
20352035
__u8 operation;
20362036
__u8 frag_pref;
20372037
__u8 length;
2038-
__u8 data[];
2038+
__u8 data[] __counted_by(length);
20392039
} __packed;
20402040

20412041
#define HCI_OP_LE_SET_EXT_ADV_ENABLE 0x2039
@@ -2061,7 +2061,7 @@ struct hci_cp_le_set_per_adv_data {
20612061
__u8 handle;
20622062
__u8 operation;
20632063
__u8 length;
2064-
__u8 data[];
2064+
__u8 data[] __counted_by(length);
20652065
} __packed;
20662066

20672067
#define HCI_OP_LE_SET_PER_ADV_ENABLE 0x2040
@@ -2162,7 +2162,7 @@ struct hci_cis {
21622162

21632163
struct hci_cp_le_create_cis {
21642164
__u8 num_cis;
2165-
struct hci_cis cis[];
2165+
struct hci_cis cis[] __counted_by(num_cis);
21662166
} __packed;
21672167

21682168
#define HCI_OP_LE_REMOVE_CIG 0x2065

net/bluetooth/hci_event.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4307,7 +4307,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
43074307
hci_dev_lock(hdev);
43084308

43094309
/* Remove connection if command failed */
4310-
for (i = 0; cp->num_cis; cp->num_cis--, i++) {
4310+
for (i = 0; i < cp->num_cis; i++) {
43114311
struct hci_conn *conn;
43124312
u16 handle;
43134313

@@ -4323,6 +4323,7 @@ static void hci_cs_le_create_cis(struct hci_dev *hdev, u8 status)
43234323
hci_conn_del(conn);
43244324
}
43254325
}
4326+
cp->num_cis = 0;
43264327

43274328
if (pending)
43284329
hci_le_create_cis_pending(hdev);

net/bluetooth/hci_sync.c

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,39 +1235,35 @@ int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance)
12351235

12361236
static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance)
12371237
{
1238-
struct {
1239-
struct hci_cp_le_set_ext_scan_rsp_data cp;
1240-
u8 data[HCI_MAX_EXT_AD_LENGTH];
1241-
} pdu;
1238+
DEFINE_FLEX(struct hci_cp_le_set_ext_scan_rsp_data, pdu, data, length,
1239+
HCI_MAX_EXT_AD_LENGTH);
12421240
u8 len;
12431241
struct adv_info *adv = NULL;
12441242
int err;
12451243

1246-
memset(&pdu, 0, sizeof(pdu));
1247-
12481244
if (instance) {
12491245
adv = hci_find_adv_instance(hdev, instance);
12501246
if (!adv || !adv->scan_rsp_changed)
12511247
return 0;
12521248
}
12531249

1254-
len = eir_create_scan_rsp(hdev, instance, pdu.data);
1250+
len = eir_create_scan_rsp(hdev, instance, pdu->data);
12551251

1256-
pdu.cp.handle = instance;
1257-
pdu.cp.length = len;
1258-
pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
1259-
pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1252+
pdu->handle = instance;
1253+
pdu->length = len;
1254+
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
1255+
pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
12601256

12611257
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA,
1262-
sizeof(pdu.cp) + len, &pdu.cp,
1258+
struct_size(pdu, data, len), pdu,
12631259
HCI_CMD_TIMEOUT);
12641260
if (err)
12651261
return err;
12661262

12671263
if (adv) {
12681264
adv->scan_rsp_changed = false;
12691265
} else {
1270-
memcpy(hdev->scan_rsp_data, pdu.data, len);
1266+
memcpy(hdev->scan_rsp_data, pdu->data, len);
12711267
hdev->scan_rsp_data_len = len;
12721268
}
12731269

@@ -1411,29 +1407,25 @@ static int hci_set_per_adv_params_sync(struct hci_dev *hdev, u8 instance,
14111407

14121408
static int hci_set_per_adv_data_sync(struct hci_dev *hdev, u8 instance)
14131409
{
1414-
struct {
1415-
struct hci_cp_le_set_per_adv_data cp;
1416-
u8 data[HCI_MAX_PER_AD_LENGTH];
1417-
} pdu;
1410+
DEFINE_FLEX(struct hci_cp_le_set_per_adv_data, pdu, data, length,
1411+
HCI_MAX_PER_AD_LENGTH);
14181412
u8 len;
14191413

1420-
memset(&pdu, 0, sizeof(pdu));
1421-
14221414
if (instance) {
14231415
struct adv_info *adv = hci_find_adv_instance(hdev, instance);
14241416

14251417
if (!adv || !adv->periodic)
14261418
return 0;
14271419
}
14281420

1429-
len = eir_create_per_adv_data(hdev, instance, pdu.data);
1421+
len = eir_create_per_adv_data(hdev, instance, pdu->data);
14301422

1431-
pdu.cp.length = len;
1432-
pdu.cp.handle = instance;
1433-
pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
1423+
pdu->length = len;
1424+
pdu->handle = instance;
1425+
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
14341426

14351427
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_DATA,
1436-
sizeof(pdu.cp) + len, &pdu,
1428+
struct_size(pdu, data, len), pdu,
14371429
HCI_CMD_TIMEOUT);
14381430
}
14391431

@@ -1727,31 +1719,27 @@ int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason)
17271719

17281720
static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
17291721
{
1730-
struct {
1731-
struct hci_cp_le_set_ext_adv_data cp;
1732-
u8 data[HCI_MAX_EXT_AD_LENGTH];
1733-
} pdu;
1722+
DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length,
1723+
HCI_MAX_EXT_AD_LENGTH);
17341724
u8 len;
17351725
struct adv_info *adv = NULL;
17361726
int err;
17371727

1738-
memset(&pdu, 0, sizeof(pdu));
1739-
17401728
if (instance) {
17411729
adv = hci_find_adv_instance(hdev, instance);
17421730
if (!adv || !adv->adv_data_changed)
17431731
return 0;
17441732
}
17451733

1746-
len = eir_create_adv_data(hdev, instance, pdu.data);
1734+
len = eir_create_adv_data(hdev, instance, pdu->data);
17471735

1748-
pdu.cp.length = len;
1749-
pdu.cp.handle = instance;
1750-
pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE;
1751-
pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG;
1736+
pdu->length = len;
1737+
pdu->handle = instance;
1738+
pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE;
1739+
pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG;
17521740

17531741
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA,
1754-
sizeof(pdu.cp) + len, &pdu.cp,
1742+
struct_size(pdu, data, len), pdu,
17551743
HCI_CMD_TIMEOUT);
17561744
if (err)
17571745
return err;
@@ -1760,7 +1748,7 @@ static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance)
17601748
if (adv) {
17611749
adv->adv_data_changed = false;
17621750
} else {
1763-
memcpy(hdev->adv_data, pdu.data, len);
1751+
memcpy(hdev->adv_data, pdu->data, len);
17641752
hdev->adv_data_len = len;
17651753
}
17661754

@@ -6493,10 +6481,8 @@ static int hci_le_create_conn_sync(struct hci_dev *hdev, void *data)
64936481

64946482
int hci_le_create_cis_sync(struct hci_dev *hdev)
64956483
{
6496-
struct {
6497-
struct hci_cp_le_create_cis cp;
6498-
struct hci_cis cis[0x1f];
6499-
} cmd;
6484+
DEFINE_FLEX(struct hci_cp_le_create_cis, cmd, cis, num_cis, 0x1f);
6485+
size_t aux_num_cis = 0;
65006486
struct hci_conn *conn;
65016487
u8 cig = BT_ISO_QOS_CIG_UNSET;
65026488

@@ -6523,8 +6509,6 @@ int hci_le_create_cis_sync(struct hci_dev *hdev)
65236509
* remains pending.
65246510
*/
65256511

6526-
memset(&cmd, 0, sizeof(cmd));
6527-
65286512
hci_dev_lock(hdev);
65296513

65306514
rcu_read_lock();
@@ -6561,7 +6545,7 @@ int hci_le_create_cis_sync(struct hci_dev *hdev)
65616545
goto done;
65626546

65636547
list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
6564-
struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis];
6548+
struct hci_cis *cis = &cmd->cis[aux_num_cis];
65656549

65666550
if (hci_conn_check_create_cis(conn) ||
65676551
conn->iso_qos.ucast.cig != cig)
@@ -6570,25 +6554,25 @@ int hci_le_create_cis_sync(struct hci_dev *hdev)
65706554
set_bit(HCI_CONN_CREATE_CIS, &conn->flags);
65716555
cis->acl_handle = cpu_to_le16(conn->parent->handle);
65726556
cis->cis_handle = cpu_to_le16(conn->handle);
6573-
cmd.cp.num_cis++;
6557+
aux_num_cis++;
65746558

6575-
if (cmd.cp.num_cis >= ARRAY_SIZE(cmd.cis))
6559+
if (aux_num_cis >= 0x1f)
65766560
break;
65776561
}
6562+
cmd->num_cis = aux_num_cis;
65786563

65796564
done:
65806565
rcu_read_unlock();
65816566

65826567
hci_dev_unlock(hdev);
65836568

6584-
if (!cmd.cp.num_cis)
6569+
if (!aux_num_cis)
65856570
return 0;
65866571

65876572
/* Wait for HCI_LE_CIS_Established */
65886573
return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CIS,
6589-
sizeof(cmd.cp) + sizeof(cmd.cis[0]) *
6590-
cmd.cp.num_cis, &cmd,
6591-
HCI_EVT_LE_CIS_ESTABLISHED,
6574+
struct_size(cmd, cis, cmd->num_cis),
6575+
cmd, HCI_EVT_LE_CIS_ESTABLISHED,
65926576
conn->conn_timeout, NULL);
65936577
}
65946578

0 commit comments

Comments
 (0)