* [PATCH] Bluetooth: hci_h4: Fix race during initialization
@ 2026-03-20 12:09 Jonathan Rissanen
2026-03-20 20:04 ` Luiz Augusto von Dentz
2026-03-27 19:20 ` patchwork-bot+bluetooth
0 siblings, 2 replies; 5+ messages in thread
From: Jonathan Rissanen @ 2026-03-20 12:09 UTC (permalink / raw)
To: Marcel Holtmann, Luiz Augusto von Dentz
Cc: linux-bluetooth, linux-kernel, kernel, Jonathan Rissanen
Commit 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during
initialization") fixed a race for hci commands sent during initialization.
However, there is still a race that happens if an hci event from one of
these commands is received before HCI_UART_REGISTERED has been set at
the end of hci_uart_register_dev(). The event will be ignored which
causes the command to fail with a timeout in the log:
"Bluetooth: hci0: command 0x1003 tx timeout"
This is because the hci event receive path (hci_uart_tty_receive ->
h4_recv) requires HCI_UART_REGISTERED to be set in h4_recv(), while the
hci command transmit path (hci_uart_send_frame -> h4_enqueue) only
requires HCI_UART_PROTO_INIT to be set in hci_uart_send_frame().
The check for HCI_UART_REGISTERED was originally added in commit
c2578202919a ("Bluetooth: Fix H4 crash from incoming UART packets")
to fix a crash caused by hu->hdev being null dereferenced. That can no
longer happen: once HCI_UART_PROTO_INIT is set in hci_uart_register_dev()
all pointers (hu, hu->priv and hu->hdev) are valid, and
hci_uart_tty_receive() already calls h4_recv() on HCI_UART_PROTO_INIT
or HCI_UART_PROTO_READY.
Remove the check for HCI_UART_REGISTERED in h4_recv() to fix the race
condition.
Signed-off-by: Jonathan Rissanen <jonathan.rissanen@axis.com>
---
drivers/bluetooth/hci_h4.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index ec017df8572c..1e9e2cad9ddf 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count)
{
struct h4_struct *h4 = hu->priv;
- if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
- return -EUNATCH;
-
h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count,
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
if (IS_ERR(h4->rx_skb)) {
---
base-commit: 05f7e89ab9731565d8a62e3b5d1ec206485eeb0b
change-id: 20260303-hci-init-fix-9657128a0104
Best regards,
--
Jonathan Rissanen <jonathan.rissanen@axis.com>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] Bluetooth: hci_h4: Fix race during initialization 2026-03-20 12:09 [PATCH] Bluetooth: hci_h4: Fix race during initialization Jonathan Rissanen @ 2026-03-20 20:04 ` Luiz Augusto von Dentz 2026-03-24 10:04 ` Jonathan Rissanen 2026-03-27 19:20 ` patchwork-bot+bluetooth 1 sibling, 1 reply; 5+ messages in thread From: Luiz Augusto von Dentz @ 2026-03-20 20:04 UTC (permalink / raw) To: Jonathan Rissanen; +Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, kernel Hi Jonathan, On Fri, Mar 20, 2026 at 8:10 AM Jonathan Rissanen <jonathan.rissanen@axis.com> wrote: > > Commit 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during > initialization") fixed a race for hci commands sent during initialization. > However, there is still a race that happens if an hci event from one of > these commands is received before HCI_UART_REGISTERED has been set at > the end of hci_uart_register_dev(). The event will be ignored which > causes the command to fail with a timeout in the log: > > "Bluetooth: hci0: command 0x1003 tx timeout" > > This is because the hci event receive path (hci_uart_tty_receive -> > h4_recv) requires HCI_UART_REGISTERED to be set in h4_recv(), while the > hci command transmit path (hci_uart_send_frame -> h4_enqueue) only > requires HCI_UART_PROTO_INIT to be set in hci_uart_send_frame(). > > The check for HCI_UART_REGISTERED was originally added in commit > c2578202919a ("Bluetooth: Fix H4 crash from incoming UART packets") > to fix a crash caused by hu->hdev being null dereferenced. That can no > longer happen: once HCI_UART_PROTO_INIT is set in hci_uart_register_dev() > all pointers (hu, hu->priv and hu->hdev) are valid, and > hci_uart_tty_receive() already calls h4_recv() on HCI_UART_PROTO_INIT > or HCI_UART_PROTO_READY. > > Remove the check for HCI_UART_REGISTERED in h4_recv() to fix the race > condition. > > Signed-off-by: Jonathan Rissanen <jonathan.rissanen@axis.com> > --- > drivers/bluetooth/hci_h4.c | 3 --- > 1 file changed, 3 deletions(-) > > diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c > index ec017df8572c..1e9e2cad9ddf 100644 > --- a/drivers/bluetooth/hci_h4.c > +++ b/drivers/bluetooth/hci_h4.c > @@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count) > { > struct h4_struct *h4 = hu->priv; > > - if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) > - return -EUNATCH; > - > h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count, > h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts)); > if (IS_ERR(h4->rx_skb)) { > > --- There is some interesting comments on: https://sashiko.dev/#/patchset/20260320-hci-init-fix-v1-1-e1960a41baf2%40axis.com It seems the issues pointed out there are unrelated to this change, but I guess it is worth double checking just in case. -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Bluetooth: hci_h4: Fix race during initialization 2026-03-20 20:04 ` Luiz Augusto von Dentz @ 2026-03-24 10:04 ` Jonathan Rissanen 2026-03-24 15:01 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 5+ messages in thread From: Jonathan Rissanen @ 2026-03-24 10:04 UTC (permalink / raw) To: Luiz Augusto von Dentz Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, kernel Hello Luiz, On 3/20/26 21:04, Luiz Augusto von Dentz wrote: > [You don't often get email from luiz.dentz@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] > > Hi Jonathan, > > On Fri, Mar 20, 2026 at 8:10 AM Jonathan Rissanen > <jonathan.rissanen@axis.com> wrote: >> >> Commit 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during >> initialization") fixed a race for hci commands sent during initialization. >> However, there is still a race that happens if an hci event from one of >> these commands is received before HCI_UART_REGISTERED has been set at >> the end of hci_uart_register_dev(). The event will be ignored which >> causes the command to fail with a timeout in the log: >> >> "Bluetooth: hci0: command 0x1003 tx timeout" >> >> This is because the hci event receive path (hci_uart_tty_receive -> >> h4_recv) requires HCI_UART_REGISTERED to be set in h4_recv(), while the >> hci command transmit path (hci_uart_send_frame -> h4_enqueue) only >> requires HCI_UART_PROTO_INIT to be set in hci_uart_send_frame(). >> >> The check for HCI_UART_REGISTERED was originally added in commit >> c2578202919a ("Bluetooth: Fix H4 crash from incoming UART packets") >> to fix a crash caused by hu->hdev being null dereferenced. That can no >> longer happen: once HCI_UART_PROTO_INIT is set in hci_uart_register_dev() >> all pointers (hu, hu->priv and hu->hdev) are valid, and >> hci_uart_tty_receive() already calls h4_recv() on HCI_UART_PROTO_INIT >> or HCI_UART_PROTO_READY. >> >> Remove the check for HCI_UART_REGISTERED in h4_recv() to fix the race >> condition. >> >> Signed-off-by: Jonathan Rissanen <jonathan.rissanen@axis.com> >> --- >> drivers/bluetooth/hci_h4.c | 3 --- >> 1 file changed, 3 deletions(-) >> >> diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c >> index ec017df8572c..1e9e2cad9ddf 100644 >> --- a/drivers/bluetooth/hci_h4.c >> +++ b/drivers/bluetooth/hci_h4.c >> @@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count) >> { >> struct h4_struct *h4 = hu->priv; >> >> - if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) >> - return -EUNATCH; >> - >> h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count, >> h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts)); >> if (IS_ERR(h4->rx_skb)) { >> >> --- > > There is some interesting comments on: > > https://sashiko.dev/#/patchset/20260320-hci-init-fix-v1-1-e1960a41baf2%40axis.com I see. Yeah there seem to be some valid comments: > If hci_register_dev() fails, the error path calls hu->proto->close(hu) > which frees the protocol-private data in hu->priv and sets it to NULL. > However, the error path fails to clear the HCI_UART_PROTO_INIT flag. I think regardless of this patch it makes sense to clear HCI_UART_PROTO_INIT if hci_register_dev() fails, since we're no longer in the initializing state. It becomes more important with this patch since it will lead to a null pointer dereference if h4_recv() is called after hci_register_dev() fails. > Additionally, since hci_uart_register_dev() is called without holding the > write-side of hu->proto_lock, can concurrent incoming UART data during > the failure window trigger a use-after-free while hu->priv is actively > being freed by h4_close()? I believe adding a write lock and clearing the bit would solve these issues: diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 2b28515de92c..5455990ab211 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -692,6 +692,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); + percpu_down_write(&hu->proto_lock); + clear_bit(HCI_UART_PROTO_INIT, &hu->flags); + percpu_up_write(&hu->proto_lock); hu->proto->close(hu); hu->hdev = NULL; hci_free_dev(hdev); > It seems the issues pointed out there are unrelated to this change, > but I guess it is worth double checking just in case. I think it's best to fix it before applying this change as it can cause null pointer dereference in error path. I can send a new patchset with the fix. -- Best regards, Jonathan ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Bluetooth: hci_h4: Fix race during initialization 2026-03-24 10:04 ` Jonathan Rissanen @ 2026-03-24 15:01 ` Luiz Augusto von Dentz 0 siblings, 0 replies; 5+ messages in thread From: Luiz Augusto von Dentz @ 2026-03-24 15:01 UTC (permalink / raw) To: Jonathan Rissanen; +Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, kernel Hi Jonathan, On Tue, Mar 24, 2026 at 6:04 AM Jonathan Rissanen <jonathan.rissanen@axis.com> wrote: > > Hello Luiz, > > On 3/20/26 21:04, Luiz Augusto von Dentz wrote: > > [You don't often get email from luiz.dentz@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] > > > > Hi Jonathan, > > > > On Fri, Mar 20, 2026 at 8:10 AM Jonathan Rissanen > > <jonathan.rissanen@axis.com> wrote: > >> > >> Commit 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during > >> initialization") fixed a race for hci commands sent during initialization. > >> However, there is still a race that happens if an hci event from one of > >> these commands is received before HCI_UART_REGISTERED has been set at > >> the end of hci_uart_register_dev(). The event will be ignored which > >> causes the command to fail with a timeout in the log: > >> > >> "Bluetooth: hci0: command 0x1003 tx timeout" > >> > >> This is because the hci event receive path (hci_uart_tty_receive -> > >> h4_recv) requires HCI_UART_REGISTERED to be set in h4_recv(), while the > >> hci command transmit path (hci_uart_send_frame -> h4_enqueue) only > >> requires HCI_UART_PROTO_INIT to be set in hci_uart_send_frame(). > >> > >> The check for HCI_UART_REGISTERED was originally added in commit > >> c2578202919a ("Bluetooth: Fix H4 crash from incoming UART packets") > >> to fix a crash caused by hu->hdev being null dereferenced. That can no > >> longer happen: once HCI_UART_PROTO_INIT is set in hci_uart_register_dev() > >> all pointers (hu, hu->priv and hu->hdev) are valid, and > >> hci_uart_tty_receive() already calls h4_recv() on HCI_UART_PROTO_INIT > >> or HCI_UART_PROTO_READY. > >> > >> Remove the check for HCI_UART_REGISTERED in h4_recv() to fix the race > >> condition. > >> > >> Signed-off-by: Jonathan Rissanen <jonathan.rissanen@axis.com> > >> --- > >> drivers/bluetooth/hci_h4.c | 3 --- > >> 1 file changed, 3 deletions(-) > >> > >> diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c > >> index ec017df8572c..1e9e2cad9ddf 100644 > >> --- a/drivers/bluetooth/hci_h4.c > >> +++ b/drivers/bluetooth/hci_h4.c > >> @@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count) > >> { > >> struct h4_struct *h4 = hu->priv; > >> > >> - if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) > >> - return -EUNATCH; > >> - > >> h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count, > >> h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts)); > >> if (IS_ERR(h4->rx_skb)) { > >> > >> --- > > > > There is some interesting comments on: > > > > https://sashiko.dev/#/patchset/20260320-hci-init-fix-v1-1-e1960a41baf2%40axis.com > > I see. Yeah there seem to be some valid comments: > > > If hci_register_dev() fails, the error path calls hu->proto->close(hu) > > which frees the protocol-private data in hu->priv and sets it to NULL. > > However, the error path fails to clear the HCI_UART_PROTO_INIT flag. > > I think regardless of this patch it makes sense to clear > HCI_UART_PROTO_INIT if hci_register_dev() fails, since we're no longer > in the initializing state. It becomes more important with this patch > since it will lead to a null pointer dereference if h4_recv() is called > after hci_register_dev() fails. > > > Additionally, since hci_uart_register_dev() is called without holding the > > write-side of hu->proto_lock, can concurrent incoming UART data during > > the failure window trigger a use-after-free while hu->priv is actively > > being freed by h4_close()? > > I believe adding a write lock and clearing the bit would solve these issues: > > diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c > index 2b28515de92c..5455990ab211 100644 > --- a/drivers/bluetooth/hci_ldisc.c > +++ b/drivers/bluetooth/hci_ldisc.c > @@ -692,6 +692,9 @@ static int hci_uart_register_dev(struct hci_uart *hu) > > if (hci_register_dev(hdev) < 0) { > BT_ERR("Can't register HCI device"); > + percpu_down_write(&hu->proto_lock); > + clear_bit(HCI_UART_PROTO_INIT, &hu->flags); > + percpu_up_write(&hu->proto_lock); > hu->proto->close(hu); > hu->hdev = NULL; > hci_free_dev(hdev); LGTM > > > > It seems the issues pointed out there are unrelated to this change, > > but I guess it is worth double checking just in case. > > I think it's best to fix it before applying this change as it can cause > null pointer dereference in error path. I can send a new patchset with > the fix. Please do. > > -- > Best regards, Jonathan -- Luiz Augusto von Dentz ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Bluetooth: hci_h4: Fix race during initialization 2026-03-20 12:09 [PATCH] Bluetooth: hci_h4: Fix race during initialization Jonathan Rissanen 2026-03-20 20:04 ` Luiz Augusto von Dentz @ 2026-03-27 19:20 ` patchwork-bot+bluetooth 1 sibling, 0 replies; 5+ messages in thread From: patchwork-bot+bluetooth @ 2026-03-27 19:20 UTC (permalink / raw) To: Jonathan Rissanen Cc: marcel, luiz.dentz, linux-bluetooth, linux-kernel, kernel Hello: This patch was applied to bluetooth/bluetooth-next.git (master) by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>: On Fri, 20 Mar 2026 13:09:49 +0100 you wrote: > Commit 5df5dafc171b ("Bluetooth: hci_uart: Fix another race during > initialization") fixed a race for hci commands sent during initialization. > However, there is still a race that happens if an hci event from one of > these commands is received before HCI_UART_REGISTERED has been set at > the end of hci_uart_register_dev(). The event will be ignored which > causes the command to fail with a timeout in the log: > > [...] Here is the summary with links: - Bluetooth: hci_h4: Fix race during initialization https://git.kernel.org/bluetooth/bluetooth-next/c/42ee54fcd11e You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-27 19:20 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-03-20 12:09 [PATCH] Bluetooth: hci_h4: Fix race during initialization Jonathan Rissanen 2026-03-20 20:04 ` Luiz Augusto von Dentz 2026-03-24 10:04 ` Jonathan Rissanen 2026-03-24 15:01 ` Luiz Augusto von Dentz 2026-03-27 19:20 ` patchwork-bot+bluetooth
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox