public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Bluetooth: hci_h4: Fix race during initialization
@ 2026-03-20 12:09 Jonathan Rissanen
  2026-03-20 13:05 ` bluez.test.bot
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ 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 related	[flat|nested] 6+ messages in thread

* RE: 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 13:05 ` bluez.test.bot
  2026-03-20 20:04 ` [PATCH] " Luiz Augusto von Dentz
  2026-03-27 19:20 ` patchwork-bot+bluetooth
  2 siblings, 0 replies; 6+ messages in thread
From: bluez.test.bot @ 2026-03-20 13:05 UTC (permalink / raw)
  To: linux-bluetooth, jonathan.rissanen

[-- Attachment #1: Type: text/plain, Size: 2833 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1069873

---Test result---

Test Summary:
CheckPatch                    PENDING   0.28 seconds
GitLint                       PENDING   0.22 seconds
SubjectPrefix                 PASS      0.11 seconds
BuildKernel                   PASS      26.60 seconds
CheckAllWarning               PASS      29.28 seconds
CheckSparse                   PASS      27.58 seconds
BuildKernel32                 PASS      25.94 seconds
TestRunnerSetup               PASS      569.53 seconds
TestRunner_l2cap-tester       PASS      28.30 seconds
TestRunner_iso-tester         FAIL      36.61 seconds
TestRunner_bnep-tester        PASS      6.29 seconds
TestRunner_mgmt-tester        FAIL      115.04 seconds
TestRunner_rfcomm-tester      PASS      9.29 seconds
TestRunner_sco-tester         FAIL      14.40 seconds
TestRunner_ioctl-tester       PASS      10.10 seconds
TestRunner_mesh-tester        FAIL      12.55 seconds
TestRunner_smp-tester         PASS      8.65 seconds
TestRunner_userchan-tester    PASS      8.98 seconds
IncrementalBuild              PENDING   0.67 seconds

Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:

##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:

##############################
Test: TestRunner_iso-tester - FAIL
Desc: Run iso-tester with test-runner
Output:
BUG: KASAN: slab-use-after-free in le_read_features_complete+0x7e/0x2b0
Total: 141, Passed: 141 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 494, Passed: 489 (99.0%), Failed: 1, Not Run: 4

Failed Test Cases
Read Exp Feature - Success                           Failed       0.108 seconds
##############################
Test: TestRunner_sco-tester - FAIL
Desc: Run sco-tester with test-runner
Output:
WARNING: possible circular locking dependency detected
BUG: sleeping function called from invalid context at net/core/sock.c:3782
Total: 30, Passed: 30 (100.0%), Failed: 0, Not Run: 0
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0

Failed Test Cases
Mesh - Send cancel - 1                               Timed out    2.740 seconds
Mesh - Send cancel - 2                               Timed out    1.996 seconds
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:



---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 6+ 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 13:05 ` bluez.test.bot
@ 2026-03-20 20:04 ` Luiz Augusto von Dentz
  2026-03-24 10:04   ` Jonathan Rissanen
  2026-03-27 19:20 ` patchwork-bot+bluetooth
  2 siblings, 1 reply; 6+ 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] 6+ messages in thread

* Re: [PATCH] Bluetooth: hci_h4: Fix race during initialization
  2026-03-20 20:04 ` [PATCH] " Luiz Augusto von Dentz
@ 2026-03-24 10:04   ` Jonathan Rissanen
  2026-03-24 15:01     ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 6+ 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 related	[flat|nested] 6+ 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; 6+ 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] 6+ 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 13:05 ` bluez.test.bot
  2026-03-20 20:04 ` [PATCH] " Luiz Augusto von Dentz
@ 2026-03-27 19:20 ` patchwork-bot+bluetooth
  2 siblings, 0 replies; 6+ 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] 6+ messages in thread

end of thread, other threads:[~2026-03-27 19:20 UTC | newest]

Thread overview: 6+ 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 13:05 ` bluez.test.bot
2026-03-20 20:04 ` [PATCH] " 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