Bluetooth: controller: Fix rx_ftr and extra overlapping memory

The the footer structure and extra bytes (rssi, resolving index etc.)
were overlapping in memory, rx_ftr was moved into the header, but the
extra and footer are still being read from the same place, extra was
written to the end. So this avoided memory corruption, but reading extra
reads wrong information.

Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Joakim Andersson 2019-05-23 14:51:14 +02:00 committed by Carles Cufí
commit 34758e8349
6 changed files with 103 additions and 110 deletions

View file

@ -2311,6 +2311,7 @@ int hci_acl_handle(struct net_buf *buf, struct net_buf **evt)
}
pdu_data = (void *)node_tx->pdu;
if (flags == BT_ACL_START_NO_FLUSH || flags == BT_ACL_START) {
pdu_data->ll_id = PDU_DATA_LLID_DATA_START;
} else {
@ -2446,13 +2447,17 @@ static inline bool scan_filter_apply(u8_t filter, u8_t *data, u8_t len)
return false;
}
static inline void le_mesh_scan_report(struct pdu_adv *adv, struct net_buf *buf,
s8_t rssi, u8_t *extra)
static inline void le_mesh_scan_report(struct pdu_adv *adv,
struct node_rx_pdu *node_rx,
struct net_buf *buf, s8_t rssi)
{
u8_t data_len = (adv->len - BDADDR_SIZE);
struct bt_hci_evt_mesh_scanning_report *mep;
struct bt_hci_evt_mesh_scan_report *sr;
u32_t instant;
#if !defined(CONFIG_BT_LL_SW_SPLIT)
u8_t *extra;
#endif
u8_t chan;
LL_ASSERT(adv->type == PDU_ADV_TYPE_NONCONN_IND);
@ -2464,9 +2469,17 @@ static inline void le_mesh_scan_report(struct pdu_adv *adv, struct net_buf *buf,
return;
}
#if defined(CONFIG_BT_LL_SW_SPLIT)
chan = node_rx->hdr.rx_ftr.chan;
instant = node_rx->hdr.rx_ftr.anchor_ticks;
#else
extra = &adv->payload[adv->len + PDU_AC_SIZE_RSSI + PDU_AC_SIZE_PRIV +
PDU_AC_SIZE_SCFP];
chan = *extra;
extra++;
instant = sys_get_le32(extra);
#endif /* CONFIG_BT_LL_SW_SPLIT */
mep = mesh_evt(buf, BT_HCI_EVT_MESH_SCANNING_REPORT,
sizeof(*mep) + sizeof(*sr));
@ -2484,7 +2497,8 @@ static inline void le_mesh_scan_report(struct pdu_adv *adv, struct net_buf *buf,
}
#endif /* CONFIG_BT_HCI_MESH_EXT */
static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
static void le_advertising_report(struct pdu_data *pdu_data,
struct node_rx_pdu *node_rx,
struct net_buf *buf)
{
const u8_t c_adv_type[] = { 0x00, 0x01, 0x03, 0xff, 0x04,
@ -2494,7 +2508,9 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
struct bt_hci_evt_le_advertising_info *adv_info;
u8_t data_len;
u8_t info_len;
#if !defined(CONFIG_BT_LL_SW_SPLIT)
u8_t *extra;
#endif
s8_t rssi;
#if defined(CONFIG_BT_CTLR_PRIVACY)
u8_t rl_idx;
@ -2505,32 +2521,37 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
s8_t *prssi;
#if defined(CONFIG_BT_LL_SW_SPLIT)
struct node_rx_pdu *node_rx;
rssi = -(node_rx->hdr.rx_ftr.rssi);
#if defined(CONFIG_BT_CTLR_PRIVACY)
rl_idx = node_rx->hdr.rx_ftr.rl_idx;
#endif /* CONFIG_BT_CTLR_PRIVACY */
#if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
direct = node_rx->hdr.rx_ftr.direct;
#endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */
node_rx = (struct node_rx_pdu *)b;
extra = (u8_t *)&(node_rx->hdr.rx_ftr.param);
#else
extra = (u8_t *)&b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len];
#endif /* CONFIG_BT_LL_SW_SPLIT */
/* The Link Layer currently returns RSSI as an absolute value */
extra = &adv->payload[adv->len];
rssi = -(*extra);
extra += 1;
extra += PDU_AC_SIZE_RSSI;
#if defined(CONFIG_BT_CTLR_PRIVACY)
rl_idx = *extra;
extra += 1;
extra += PDU_AC_SIZE_PRIV;
#endif
#if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
direct = *extra;
extra += PDU_AC_SIZE_SCFP;
#endif
#endif /* CONFIG_BT_LL_SW_SPLIT */
/* Update current RPA */
#if defined(CONFIG_BT_CTLR_PRIVACY)
if (adv->tx_addr) {
/* Update current RPA */
ll_rl_crpa_set(0x00, NULL, rl_idx, &adv->adv_ind.addr[0]);
}
#endif /* CONFIG_BT_CTLR_PRIVACY */
#if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
direct = *extra;
extra += 1;
if (direct) {
#if defined(CONFIG_BT_CTLR_PRIVACY)
le_dir_adv_report(adv, buf, rssi, rl_idx);
@ -2542,8 +2563,8 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
#endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */
#if defined(CONFIG_BT_HCI_MESH_EXT)
if (((struct node_rx_pdu *)b)->hdr.type == NODE_RX_TYPE_MESH_REPORT) {
le_mesh_scan_report(adv, buf, rssi, extra);
if (node_rx->hdr.type == NODE_RX_TYPE_MESH_REPORT) {
le_mesh_scan_report(adv, node_rx, buf, rssi);
return;
}
#endif /* CONFIG_BT_HCI_MESH_EXT */
@ -2599,24 +2620,23 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
}
#if defined(CONFIG_BT_CTLR_ADV_EXT)
static void le_adv_ext_report(struct pdu_data *pdu_data, u8_t *b,
static void le_adv_ext_report(struct pdu_data *pdu_data,
struct node_rx_pdu *node_rx,
struct net_buf *buf, u8_t phy)
{
struct pdu_adv *adv = (void *)pdu_data;
s8_t rssi;
#if !defined(CONFIG_BT_LL_SW_SPLIT)
u8_t *extra;
#endif
#if defined(CONFIG_BT_LL_SW_SPLIT)
struct node_rx_pdu *node_rx;
node_rx = (struct node_rx_pdu *)b;
extra = (u8_t *)&(node_rx->hdr.rx_ftr.param);
#else
extra = (u8_t *)&b[offsetof(struct radio_pdu_node_rx, pdu_data) +
offsetof(struct pdu_adv, payload) + adv->len];
#endif /* CONFIG_BT_LL_SW_SPLIT */
/* The Link Layer currently returns RSSI as an absolute value */
rssi = -(node_rx->hdr.rx_ftr.rssi);
#else
extra = &adv->payload[adv->len];
rssi = -(*extra);
#endif /* CONFIG_BT_LL_SW_SPLIT */
BT_DBG("phy= 0x%x, type= 0x%x, len= %u, tat= %u, rat= %u, rssi=%d dB",
phy, adv->type, adv->len, adv->tx_addr, adv->rx_addr, rssi);
@ -2667,22 +2687,25 @@ no_ext_hdr:
return;
}
static void le_adv_ext_1M_report(struct pdu_data *pdu_data, u8_t *b,
static void le_adv_ext_1M_report(struct pdu_data *pdu_data,
struct node_rx_pdu *node_rx,
struct net_buf *buf)
{
le_adv_ext_report(pdu_data, b, buf, BIT(0));
le_adv_ext_report(pdu_data, node_rx, buf, BIT(0));
}
static void le_adv_ext_coded_report(struct pdu_data *pdu_data, u8_t *b,
static void le_adv_ext_coded_report(struct pdu_data *pdu_data,
struct node_rx_pdu *node_rx,
struct net_buf *buf)
{
le_adv_ext_report(pdu_data, b, buf, BIT(2));
le_adv_ext_report(pdu_data, node_rx, buf, BIT(2));
}
#endif /* CONFIG_BT_CTLR_ADV_EXT */
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
static void le_scan_req_received(struct pdu_data *pdu_data, u8_t *b,
static void le_scan_req_received(struct pdu_data *pdu_data,
struct node_rx_pdu *node_rx,
struct net_buf *buf)
{
struct pdu_adv *adv = (void *)pdu_data;
@ -2695,7 +2718,9 @@ static void le_scan_req_received(struct pdu_data *pdu_data, u8_t *b,
char addr_str[BT_ADDR_LE_STR_LEN];
bt_addr_le_t addr;
u8_t handle;
#if !defined(CONFIG_BT_LL_SW_SPLIT)
u8_t *extra;
#endif
s8_t rssi;
handle = 0U;
@ -2704,19 +2729,12 @@ static void le_scan_req_received(struct pdu_data *pdu_data, u8_t *b,
sizeof(bt_addr_t));
#if defined(CONFIG_BT_LL_SW_SPLIT)
struct node_rx_pdu *node_rx;
node_rx = (struct node_rx_pdu *)b;
extra = (u8_t *)&(node_rx->hdr.rx_ftr.param);
#else
extra = (u8_t *)&b[offsetof(struct radio_pdu_node_rx,
pdu_data) +
offsetof(struct pdu_adv, payload) +
adv->len];
#endif /* CONFIG_BT_LL_SW_SPLIT */
/* The Link Layer currently returns RSSI as an absolute value */
rssi = -(node_rx->hdr.rx_ftr.rssi);
#else
extra = &adv->payload[adv->len];
rssi = -(*extra);
#endif /* CONFIG_BT_LL_SW_SPLIT */
bt_addr_le_to_str(&addr, addr_str, sizeof(addr_str));
@ -2963,7 +2981,8 @@ static void le_phy_upd_complete(struct pdu_data *pdu_data, u16_t handle,
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_HCI_MESH_EXT)
static void mesh_adv_cplt(struct pdu_data *pdu_data, u8_t *b,
static void mesh_adv_cplt(struct pdu_data *pdu_data,
struct node_rx_pdu *node_rx,
struct net_buf *buf)
{
struct bt_hci_evt_mesh_adv_complete *mep;
@ -2976,9 +2995,6 @@ static void mesh_adv_cplt(struct pdu_data *pdu_data, u8_t *b,
static void encode_control(struct node_rx_pdu *node_rx,
struct pdu_data *pdu_data, struct net_buf *buf)
{
#if defined(CONFIG_BT_OBSERVER) || defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
u8_t *b = (u8_t *)node_rx;
#endif /* CONFIG_BT_OBSERVER || CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
u16_t handle;
handle = node_rx->hdr.handle;
@ -2986,23 +3002,23 @@ static void encode_control(struct node_rx_pdu *node_rx,
switch (node_rx->hdr.type) {
#if defined(CONFIG_BT_OBSERVER)
case NODE_RX_TYPE_REPORT:
le_advertising_report(pdu_data, b, buf);
le_advertising_report(pdu_data, node_rx, buf);
break;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
case NODE_RX_TYPE_EXT_1M_REPORT:
le_adv_ext_1M_report(pdu_data, b, buf);
le_adv_ext_1M_report(pdu_data, node_rx, buf);
break;
case NODE_RX_TYPE_EXT_CODED_REPORT:
le_adv_ext_coded_report(pdu_data, b, buf);
le_adv_ext_coded_report(pdu_data, node_rx, buf);
break;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
#endif /* CONFIG_BT_OBSERVER */
#if defined(CONFIG_BT_CTLR_SCAN_REQ_NOTIFY)
case NODE_RX_TYPE_SCAN_REQ:
le_scan_req_received(pdu_data, b, buf);
le_scan_req_received(pdu_data, node_rx, buf);
break;
#endif /* CONFIG_BT_CTLR_SCAN_REQ_NOTIFY */
@ -3077,11 +3093,11 @@ static void encode_control(struct node_rx_pdu *node_rx,
#if defined(CONFIG_BT_HCI_MESH_EXT)
case NODE_RX_TYPE_MESH_ADV_CPLT:
mesh_adv_cplt(pdu_data, b, buf);
mesh_adv_cplt(pdu_data, node_rx, buf);
return;
case NODE_RX_TYPE_MESH_REPORT:
le_advertising_report(pdu_data, b, buf);
le_advertising_report(pdu_data, node_rx, buf);
return;
#endif /* CONFIG_BT_HCI_MESH_EXT */
@ -3302,9 +3318,7 @@ void hci_acl_encode(struct node_rx_pdu *node_rx, struct net_buf *buf)
#if defined(CONFIG_BT_LL_SW_SPLIT)
pdu_data = (void *)node_rx->pdu;
#else
u8_t *b = (u8_t *)node_rx;
pdu_data = (void *)&b[offsetof(struct radio_pdu_node_rx, pdu_data)];
pdu_data = (void *)((struct radio_pdu_node_rx *)node_rx)->pdu_data;
#endif /* CONFIG_BT_LL_SW_SPLIT */
switch (pdu_data->ll_id) {
@ -3349,9 +3363,7 @@ void hci_evt_encode(struct node_rx_pdu *node_rx, struct net_buf *buf)
#if defined(CONFIG_BT_LL_SW_SPLIT)
pdu_data = (void *)node_rx->pdu;
#else
u8_t *b = (u8_t *)node_rx;
pdu_data = (void *)&b[offsetof(struct radio_pdu_node_rx, pdu_data)];
pdu_data = (void *)((struct radio_pdu_node_rx *)node_rx)->pdu_data;
#endif /* CONFIG_BT_LL_SW_SPLIT */
if (node_rx->hdr.type != NODE_RX_TYPE_DC_PDU) {
@ -3387,9 +3399,7 @@ s8_t hci_get_class(struct node_rx_pdu *node_rx)
#if defined(CONFIG_BT_LL_SW_SPLIT)
pdu_data = (void *)node_rx->pdu;
#else
u8_t *b = (u8_t *)node_rx;
pdu_data = (void *)&b[offsetof(struct radio_pdu_node_rx, pdu_data)];
pdu_data = (void *)((struct radio_pdu_node_rx *)node_rx)->pdu_data;
#endif /* CONFIG_BT_LL_SW_SPLIT */
if (node_rx->hdr.type != NODE_RX_TYPE_DC_PDU) {

View file

@ -190,6 +190,16 @@ struct node_rx_ftr {
u32_t ticks_anchor;
u32_t us_radio_end;
u32_t us_radio_rdy;
u8_t rssi;
#if defined(CONFIG_BT_CTLR_PRIVACY)
u8_t rl_idx;
#endif /* CONFIG_BT_CTLR_PRIVACY */
#if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
u8_t direct;
#endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */
#if defined(CONFIG_BT_HCI_MESH_EXT)
u8_t chan_idx;
#endif /* CONFIG_BT_HCI_MESH_EXT */
};

View file

@ -718,17 +718,12 @@ static inline int isr_rx_pdu(struct lll_adv *lll,
radio_tx_chain_delay_get(0, 0);
ftr->us_radio_rdy = radio_rx_ready_delay_get(0, 0);
#if defined(CONFIG_BT_CTLR_PRIVACY)
ftr->rl_idx = irkmatch_ok ? rl_idx : FILTER_IDX_NONE;
#endif /* CONFIG_BT_CTLR_PRIVACY */
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
ftr->extra = ull_pdu_rx_alloc();
if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY)) {
*((u8_t *)ftr->extra) = irkmatch_ok ?
rl_idx :
FILTER_IDX_NONE;
}
} else if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY)) {
ftr->extra = (void *)((u32_t)(irkmatch_ok ?
rl_idx :
FILTER_IDX_NONE));
}
ull_rx_put(rx->hdr.link, rx);
@ -790,7 +785,8 @@ static inline int isr_rx_sr_report(struct pdu_adv *pdu_adv_rx,
pdu_adv = (void *)node_rx->pdu;
pdu_len = offsetof(struct pdu_adv, payload) + pdu_adv_rx->len;
memcpy(pdu_adv, pdu_adv_rx, pdu_len);
((u8_t *)pdu_adv)[pdu_len] = (rssi_ready) ? (radio_rssi_get() & 0x7f) :
node_rx->hdr.rx_ftr.rssi = (rssi_ready) ? (radio_rssi_get() & 0x7f) :
0x7f;
ull_rx_put(node_rx->hdr.link, node_rx);

View file

@ -786,17 +786,12 @@ static inline u32_t isr_rx_pdu(struct lll_scan *lll, u8_t devmatch_ok,
radio_tx_chain_delay_get(0, 0);
ftr->us_radio_rdy = radio_tx_ready_delay_get(0, 0);
#if defined(CONFIG_BT_CTLR_PRIVACY)
ftr->rl_idx = irkmatch_ok ? rl_idx : FILTER_IDX_NONE;
#endif /* CONFIG_BT_CTLR_PRIVACY */
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
ftr->extra = ull_pdu_rx_alloc();
if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY)) {
*((u8_t *)ftr->extra) = irkmatch_ok ?
rl_idx :
FILTER_IDX_NONE;
}
} else if (IS_ENABLED(CONFIG_BT_CTLR_PRIVACY)) {
ftr->extra = (void *)((u32_t)(irkmatch_ok ?
rl_idx :
FILTER_IDX_NONE));
}
ull_rx_put(rx->hdr.link, rx);
@ -1014,7 +1009,6 @@ static u32_t isr_rx_scan_report(struct lll_scan *lll, u8_t rssi_ready,
{
struct node_rx_pdu *node_rx;
struct pdu_adv *pdu_adv_rx;
u8_t *extra;
node_rx = ull_pdu_rx_alloc_peek(3);
if (!node_rx) {
@ -1053,28 +1047,23 @@ static u32_t isr_rx_scan_report(struct lll_scan *lll, u8_t rssi_ready,
}
pdu_adv_rx = (void *)node_rx->pdu;
extra = (u8_t *)&(node_rx->hdr.rx_ftr.param);
/* save the RSSI value */
*extra = (rssi_ready) ? (radio_rssi_get() & 0x7f) : 0x7f;
extra += PDU_AC_SIZE_RSSI;
node_rx->hdr.rx_ftr.rssi = (rssi_ready) ?
(radio_rssi_get() & 0x7f)
: 0x7f;
#if defined(CONFIG_BT_CTLR_PRIVACY)
/* save the resolving list index. */
*extra = rl_idx;
extra += PDU_AC_SIZE_PRIV;
node_rx->hdr.rx_ftr.rl_idx = rl_idx;
#endif /* CONFIG_BT_CTLR_PRIVACY */
#if defined(CONFIG_BT_CTLR_EXT_SCAN_FP)
/* save the directed adv report flag */
*extra = dir_report ? 1 : 0;
extra += PDU_AC_SIZE_SCFP;
node_rx->hdr.rx_ftr.direct = dir_report;
#endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */
#if defined(CONFIG_BT_HCI_MESH_EXT)
if (node_rx->hdr.type == NODE_RX_TYPE_MESH_REPORT) {
/* save the directed adv report flag */
*extra = _radio.scanner.chan - 1;
extra++;
sys_put_le32(_radio.ticks_anchor, extra);
/* save channel and anchor point ticks. */
node_rx->hdr.rx_ftr.chan = _radio.scanner.chan - 1;
node_rx->hdr.rx_ftr.ticks_anchor = _radio.ticks_anchor;
}
#endif /* CONFIG_BT_CTLR_EXT_SCAN_FP */

View file

@ -436,7 +436,7 @@ void ull_master_setup(memq_link_t *link, struct node_rx_hdr *rx,
u8_t own_addr_type = pdu_tx->tx_addr;
u8_t own_addr[BDADDR_SIZE];
u8_t peer_addr[BDADDR_SIZE];
u8_t rl_idx;
u8_t rl_idx = ftr->rl_idx;
memcpy(own_addr, &pdu_tx->connect_ind.init_addr[0], BDADDR_SIZE);
memcpy(peer_addr, &pdu_tx->connect_ind.adv_addr[0], BDADDR_SIZE);
@ -453,12 +453,6 @@ void ull_master_setup(memq_link_t *link, struct node_rx_hdr *rx,
cc->own_addr_type = own_addr_type;
memcpy(&cc->own_addr[0], &own_addr[0], BDADDR_SIZE);
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
rl_idx = *((u8_t *)ftr->extra);
} else {
rl_idx = (u8_t)((u32_t)ftr->extra & 0xFF);
}
if (rl_idx != FILTER_IDX_NONE) {
/* TODO: store rl_idx instead if safe */
/* Store identity address */

View file

@ -125,7 +125,7 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
#if defined(CONFIG_BT_CTLR_PRIVACY)
u8_t own_addr_type = pdu_adv->rx_addr;
u8_t own_addr[BDADDR_SIZE];
u8_t rl_idx;
u8_t rl_idx = ftr->rl_idx;
memcpy(own_addr, &pdu_adv->connect_ind.adv_addr[0], BDADDR_SIZE);
#endif
@ -143,12 +143,6 @@ void ull_slave_setup(memq_link_t *link, struct node_rx_hdr *rx,
cc->own_addr_type = own_addr_type;
memcpy(&cc->own_addr[0], &own_addr[0], BDADDR_SIZE);
if (IS_ENABLED(CONFIG_BT_CTLR_CHAN_SEL_2)) {
rl_idx = *((u8_t *)ftr->extra);
} else {
rl_idx = (u8_t)((u32_t)ftr->extra & 0xFF);
}
if (rl_idx != FILTER_IDX_NONE) {
/* TODO: store rl_idx instead if safe */
/* Store identity address */