From 3087c5cc76c1dff97ce3924e16b1b7b12aaf18d4 Mon Sep 17 00:00:00 2001 From: Ivan Iushkov Date: Tue, 6 Feb 2024 09:34:16 +0100 Subject: [PATCH] [nrf fromtree] 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 (cherry picked from commit a3cbf8e2aca97548c9a7380c76b8bf8e0161006a) 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 e6fbe2144f8..b8faa1efcae 100644 --- a/subsys/bluetooth/host/l2cap.c +++ b/subsys/bluetooth/host/l2cap.c @@ -977,7 +977,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 e9a10ff8d72..3a33ff293c6 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);