From a3cbf8e2aca97548c9a7380c76b8bf8e0161006a Mon Sep 17 00:00:00 2001 From: Ivan Iushkov Date: Tue, 6 Feb 2024 09:34:16 +0100 Subject: [PATCH] Bluetooth: fixing null-pointer dereference in l2cap channel destroyer During local testing with UBSAN enabled, warning was reported: bluetooth/host/l2cap.c:980:25: runtime error: member access within null pointer of type 'struct k_work_q' It turned out that le_chan->rtx_work.queue can be NULL. Since null-pointer dereference is a UB, additional check was added to ensure we don't access `le_chan->rtx_work.queue->thread` when `le_chan->rtx_work.queue == NULL` The same changes applied to l2cap_br.c Signed-off-by: Ivan Iushkov --- subsys/bluetooth/host/l2cap.c | 4 +++- subsys/bluetooth/host/l2cap_br.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/subsys/bluetooth/host/l2cap.c b/subsys/bluetooth/host/l2cap.c index e79e878ccbf6..9952700b7c0d 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -962,7 +962,9 @@ static void l2cap_chan_destroy(struct bt_l2cap_chan *chan) * In the case where we are in the context of executing the rtx_work * item, we don't sync as it will deadlock the workqueue. */ - if (k_current_get() != &le_chan->rtx_work.queue->thread) { + struct k_work_q *rtx_work_queue = le_chan->rtx_work.queue; + + if (rtx_work_queue == NULL || k_current_get() != &rtx_work_queue->thread) { k_work_cancel_delayable_sync(&le_chan->rtx_work, &le_chan->rtx_sync); } else { k_work_cancel_delayable(&le_chan->rtx_work); diff --git a/subsys/bluetooth/host/l2cap_br.c b/subsys/bluetooth/host/l2cap_br.c index aaef1e3d1f10..a7884858ad23 100644 --- a/subsys/bluetooth/host/l2cap_br.c +++ b/subsys/bluetooth/host/l2cap_br.c @@ -165,7 +165,9 @@ static void l2cap_br_chan_destroy(struct bt_l2cap_chan *chan) * In the case where we are in the context of executing the rtx_work * item, we don't sync as it will deadlock the workqueue. */ - if (k_current_get() != &br_chan->rtx_work.queue->thread) { + struct k_work_q *rtx_work_queue = br_chan->rtx_work.queue; + + if (rtx_work_queue == NULL || k_current_get() != &rtx_work_queue->thread) { k_work_cancel_delayable_sync(&br_chan->rtx_work, &br_chan->rtx_sync); } else { k_work_cancel_delayable(&br_chan->rtx_work);