Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: https://github.com/KSPP/linux/issues/202
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Gustavo A. R. Silva and committed by
Luiz Augusto von Dentz
c4585edf 3487cda2

+40 -55
+4 -4
include/net/bluetooth/hci.h
··· 2026 2026 __u8 operation; 2027 2027 __u8 frag_pref; 2028 2028 __u8 length; 2029 - __u8 data[]; 2029 + __u8 data[] __counted_by(length); 2030 2030 } __packed; 2031 2031 2032 2032 #define HCI_OP_LE_SET_EXT_SCAN_RSP_DATA 0x2038 ··· 2035 2035 __u8 operation; 2036 2036 __u8 frag_pref; 2037 2037 __u8 length; 2038 - __u8 data[]; 2038 + __u8 data[] __counted_by(length); 2039 2039 } __packed; 2040 2040 2041 2041 #define HCI_OP_LE_SET_EXT_ADV_ENABLE 0x2039 ··· 2061 2061 __u8 handle; 2062 2062 __u8 operation; 2063 2063 __u8 length; 2064 - __u8 data[]; 2064 + __u8 data[] __counted_by(length); 2065 2065 } __packed; 2066 2066 2067 2067 #define HCI_OP_LE_SET_PER_ADV_ENABLE 0x2040 ··· 2162 2162 2163 2163 struct hci_cp_le_create_cis { 2164 2164 __u8 num_cis; 2165 - struct hci_cis cis[]; 2165 + struct hci_cis cis[] __counted_by(num_cis); 2166 2166 } __packed; 2167 2167 2168 2168 #define HCI_OP_LE_REMOVE_CIG 0x2065
+2 -1
net/bluetooth/hci_event.c
··· 4307 4307 hci_dev_lock(hdev); 4308 4308 4309 4309 /* 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++) { 4311 4311 struct hci_conn *conn; 4312 4312 u16 handle; 4313 4313 ··· 4323 4323 hci_conn_del(conn); 4324 4324 } 4325 4325 } 4326 + cp->num_cis = 0; 4326 4327 4327 4328 if (pending) 4328 4329 hci_le_create_cis_pending(hdev);
+34 -50
net/bluetooth/hci_sync.c
··· 1235 1235 1236 1236 static int hci_set_ext_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance) 1237 1237 { 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); 1242 1240 u8 len; 1243 1241 struct adv_info *adv = NULL; 1244 1242 int err; 1245 - 1246 - memset(&pdu, 0, sizeof(pdu)); 1247 1243 1248 1244 if (instance) { 1249 1245 adv = hci_find_adv_instance(hdev, instance); ··· 1247 1251 return 0; 1248 1252 } 1249 1253 1250 - len = eir_create_scan_rsp(hdev, instance, pdu.data); 1254 + len = eir_create_scan_rsp(hdev, instance, pdu->data); 1251 1255 1252 - pdu.cp.handle = instance; 1253 - pdu.cp.length = len; 1254 - pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; 1255 - pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; 1256 + pdu->handle = instance; 1257 + pdu->length = len; 1258 + pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE; 1259 + pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG; 1256 1260 1257 1261 err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_SCAN_RSP_DATA, 1258 - sizeof(pdu.cp) + len, &pdu.cp, 1262 + struct_size(pdu, data, len), pdu, 1259 1263 HCI_CMD_TIMEOUT); 1260 1264 if (err) 1261 1265 return err; ··· 1263 1267 if (adv) { 1264 1268 adv->scan_rsp_changed = false; 1265 1269 } else { 1266 - memcpy(hdev->scan_rsp_data, pdu.data, len); 1270 + memcpy(hdev->scan_rsp_data, pdu->data, len); 1267 1271 hdev->scan_rsp_data_len = len; 1268 1272 } 1269 1273 ··· 1407 1411 1408 1412 static int hci_set_per_adv_data_sync(struct hci_dev *hdev, u8 instance) 1409 1413 { 1410 - struct { 1411 - struct hci_cp_le_set_per_adv_data cp; 1412 - u8 data[HCI_MAX_PER_AD_LENGTH]; 1413 - } pdu; 1414 + DEFINE_FLEX(struct hci_cp_le_set_per_adv_data, pdu, data, length, 1415 + HCI_MAX_PER_AD_LENGTH); 1414 1416 u8 len; 1415 - 1416 - memset(&pdu, 0, sizeof(pdu)); 1417 1417 1418 1418 if (instance) { 1419 1419 struct adv_info *adv = hci_find_adv_instance(hdev, instance); ··· 1418 1426 return 0; 1419 1427 } 1420 1428 1421 - len = eir_create_per_adv_data(hdev, instance, pdu.data); 1429 + len = eir_create_per_adv_data(hdev, instance, pdu->data); 1422 1430 1423 - pdu.cp.length = len; 1424 - pdu.cp.handle = instance; 1425 - pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; 1431 + pdu->length = len; 1432 + pdu->handle = instance; 1433 + pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE; 1426 1434 1427 1435 return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PER_ADV_DATA, 1428 - sizeof(pdu.cp) + len, &pdu, 1436 + struct_size(pdu, data, len), pdu, 1429 1437 HCI_CMD_TIMEOUT); 1430 1438 } 1431 1439 ··· 1719 1727 1720 1728 static int hci_set_ext_adv_data_sync(struct hci_dev *hdev, u8 instance) 1721 1729 { 1722 - struct { 1723 - struct hci_cp_le_set_ext_adv_data cp; 1724 - u8 data[HCI_MAX_EXT_AD_LENGTH]; 1725 - } pdu; 1730 + DEFINE_FLEX(struct hci_cp_le_set_ext_adv_data, pdu, data, length, 1731 + HCI_MAX_EXT_AD_LENGTH); 1726 1732 u8 len; 1727 1733 struct adv_info *adv = NULL; 1728 1734 int err; 1729 - 1730 - memset(&pdu, 0, sizeof(pdu)); 1731 1735 1732 1736 if (instance) { 1733 1737 adv = hci_find_adv_instance(hdev, instance); ··· 1731 1743 return 0; 1732 1744 } 1733 1745 1734 - len = eir_create_adv_data(hdev, instance, pdu.data); 1746 + len = eir_create_adv_data(hdev, instance, pdu->data); 1735 1747 1736 - pdu.cp.length = len; 1737 - pdu.cp.handle = instance; 1738 - pdu.cp.operation = LE_SET_ADV_DATA_OP_COMPLETE; 1739 - pdu.cp.frag_pref = LE_SET_ADV_DATA_NO_FRAG; 1748 + pdu->length = len; 1749 + pdu->handle = instance; 1750 + pdu->operation = LE_SET_ADV_DATA_OP_COMPLETE; 1751 + pdu->frag_pref = LE_SET_ADV_DATA_NO_FRAG; 1740 1752 1741 1753 err = __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_EXT_ADV_DATA, 1742 - sizeof(pdu.cp) + len, &pdu.cp, 1754 + struct_size(pdu, data, len), pdu, 1743 1755 HCI_CMD_TIMEOUT); 1744 1756 if (err) 1745 1757 return err; ··· 1748 1760 if (adv) { 1749 1761 adv->adv_data_changed = false; 1750 1762 } else { 1751 - memcpy(hdev->adv_data, pdu.data, len); 1763 + memcpy(hdev->adv_data, pdu->data, len); 1752 1764 hdev->adv_data_len = len; 1753 1765 } 1754 1766 ··· 6481 6493 6482 6494 int hci_le_create_cis_sync(struct hci_dev *hdev) 6483 6495 { 6484 - struct { 6485 - struct hci_cp_le_create_cis cp; 6486 - struct hci_cis cis[0x1f]; 6487 - } cmd; 6496 + DEFINE_FLEX(struct hci_cp_le_create_cis, cmd, cis, num_cis, 0x1f); 6497 + size_t aux_num_cis = 0; 6488 6498 struct hci_conn *conn; 6489 6499 u8 cig = BT_ISO_QOS_CIG_UNSET; 6490 6500 ··· 6508 6522 * being established; until all the events are generated, the command 6509 6523 * remains pending. 6510 6524 */ 6511 - 6512 - memset(&cmd, 0, sizeof(cmd)); 6513 6525 6514 6526 hci_dev_lock(hdev); 6515 6527 ··· 6545 6561 goto done; 6546 6562 6547 6563 list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) { 6548 - struct hci_cis *cis = &cmd.cis[cmd.cp.num_cis]; 6564 + struct hci_cis *cis = &cmd->cis[aux_num_cis]; 6549 6565 6550 6566 if (hci_conn_check_create_cis(conn) || 6551 6567 conn->iso_qos.ucast.cig != cig) ··· 6554 6570 set_bit(HCI_CONN_CREATE_CIS, &conn->flags); 6555 6571 cis->acl_handle = cpu_to_le16(conn->parent->handle); 6556 6572 cis->cis_handle = cpu_to_le16(conn->handle); 6557 - cmd.cp.num_cis++; 6573 + aux_num_cis++; 6558 6574 6559 - if (cmd.cp.num_cis >= ARRAY_SIZE(cmd.cis)) 6575 + if (aux_num_cis >= 0x1f) 6560 6576 break; 6561 6577 } 6578 + cmd->num_cis = aux_num_cis; 6562 6579 6563 6580 done: 6564 6581 rcu_read_unlock(); 6565 6582 6566 6583 hci_dev_unlock(hdev); 6567 6584 6568 - if (!cmd.cp.num_cis) 6585 + if (!aux_num_cis) 6569 6586 return 0; 6570 6587 6571 6588 /* Wait for HCI_LE_CIS_Established */ 6572 6589 return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CIS, 6573 - sizeof(cmd.cp) + sizeof(cmd.cis[0]) * 6574 - cmd.cp.num_cis, &cmd, 6575 - HCI_EVT_LE_CIS_ESTABLISHED, 6590 + struct_size(cmd, cis, cmd->num_cis), 6591 + cmd, HCI_EVT_LE_CIS_ESTABLISHED, 6576 6592 conn->conn_timeout, NULL); 6577 6593 } 6578 6594