Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [RFC PATCH BlueZ] monitor: Fix RAS CS step mode parsing issues
From: patchwork-bot+bluetooth @ 2026-05-12 19:20 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <20260508191728.428868-1-luiz.dentz@gmail.com>

Hello:

This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Fri,  8 May 2026 15:17:28 -0400 you wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> Fix double space typo in print_ranging_steps signature.
> 
> Fix ToA_ToD sign extension using proper cast via (uint32_t)(int16_t)
> instead of unconditionally OR-ing with 0xFFFF0000 which corrupts
> positive values.
> 
> [...]

Here is the summary with links:
  - [RFC,BlueZ] monitor: Fix RAS CS step mode parsing issues
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=4cedd8f9b886

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH BlueZ] pbap: Fix not checking Database Identifier length
From: patchwork-bot+bluetooth @ 2026-05-12 19:20 UTC (permalink / raw)
  To: =?utf-8?b?RnLDqWTDqXJpYyBEYW5pcyA8ZnJlZGVyaWMuZGFuaXNAY29sbGFib3JhLmNvbT4=?=
  Cc: linux-bluetooth
In-Reply-To: <20260512083750.178053-1-frederic.danis@collabora.com>

Hello:

This patch was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Tue, 12 May 2026 10:37:50 +0200 you wrote:
> Database Identifier is supposed to be 16 bytes values.
> 
> A paired Bluetooth device acting as a PBAP server can overflow the
> heap in obexd by up to 239 bytes into adjacent allocations by returning
> a DATABASEID_TAG application parameter with an oversized length.
> With both length and content fully attacker-controlled, this enables
> standard glibc heap exploitation primitives (tcache/fastbin poisoning)
> leading to remote code execution in the obexd process.
> 
> [...]

Here is the summary with links:
  - [BlueZ] pbap: Fix not checking Database Identifier length
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=6ba04fad369f

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* [bluez/bluez] 4cedd8: monitor: Fix RAS CS step mode parsing issues
From: fdanis-oss @ 2026-05-12 19:23 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/master
  Home:   https://github.com/bluez/bluez
  Commit: 4cedd8f9b886221f857c67295b1c1ed6b285ea3d
      https://github.com/bluez/bluez/commit/4cedd8f9b886221f857c67295b1c1ed6b285ea3d
  Author: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M monitor/att.c

  Log Message:
  -----------
  monitor: Fix RAS CS step mode parsing issues

Fix double space typo in print_ranging_steps signature.

Fix ToA_ToD sign extension using proper cast via (uint32_t)(int16_t)
instead of unconditionally OR-ing with 0xFFFF0000 which corrupts
positive values.

Refactor print_step_mode_3 to reuse print_step_mode_1 and
print_step_mode_2 eliminating ~90 lines of duplicated code.

Initialize first_segment to false so the error path via goto done
does not incorrectly print remaining data when the segmentation
header was never parsed.

Improve Mode 0 step data length heuristic with better alignment
check and clearer documentation of the limitation.

Assisted-by: OpenCode:claude-opus-4.6


  Commit: ca2b39b0c08e810643eb53fb3fa3f7a49ff24dcd
      https://github.com/bluez/bluez/commit/ca2b39b0c08e810643eb53fb3fa3f7a49ff24dcd
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M lib/bluetooth/hci.c
    M src/main.c
    M src/shared/gatt-server.c

  Log Message:
  -----------
  all: Remove more unneeded MIN/MAX macro definition


  Commit: 2e0533f977cc5f1c3a62270aedebbefd14fa7a5a
      https://github.com/bluez/bluez/commit/2e0533f977cc5f1c3a62270aedebbefd14fa7a5a
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M src/shared/util.h
    M unit/test-util.c

  Log Message:
  -----------
  shared/util: Add helper for "cleanup" variable attribute

Use the widespread "cleanup" variable attribute:
https://gcc.gnu.org/onlinedocs/gcc/Common-Attributes.html#index-cleanup

It is implemented by both GCC and clang on platforms where bluez is
used, and can help reduce memory leaks, while improving readability.

This implements:
- generic cleanup (_cleanup_free_)
- cleanup with specific free function (_cleanup_())
- cleanup for specific types (_cleanup_type_(type))
- cleanup for file descriptors
- capturing a variable before it is freed (so it is only freed in error
  paths for example, _steal_() and _steal_fd())

This commit includes tests which should cover all those new helpers.

See also:
https://systemd.io/CODING_STYLE/#memory-allocation
https://docs.gtk.org/glib/auto-cleanup.html


  Commit: 9ba6c13df5fb461237e5f4e44f81eee3a21b415a
      https://github.com/bluez/bluez/commit/9ba6c13df5fb461237e5f4e44f81eee3a21b415a
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M doc/maintainer-guidelines.rst

  Log Message:
  -----------
  doc: Recommend using _cleanup_ and friends


  Commit: 140e3569295c662a8a9e12aec1cdc72c027361d6
      https://github.com/bluez/bluez/commit/140e3569295c662a8a9e12aec1cdc72c027361d6
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M src/main.c

  Log Message:
  -----------
  main: Use _cleanup_() to simplify configuration parsing

Use helpers to simplify temporary string usage, and cleanup in error
paths.


  Commit: e33f5027b898a84e664752d92b16a2b8ac25eda3
      https://github.com/bluez/bluez/commit/e33f5027b898a84e664752d92b16a2b8ac25eda3
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M client/mgmt.c

  Log Message:
  -----------
  client: Use _cleanup_fd_ to simplify urandom access

fd gets auto-closed before exiting the scope.


  Commit: 02aa9a8cfe6af80d59cca0851608ed87a708e0ed
      https://github.com/bluez/bluez/commit/02aa9a8cfe6af80d59cca0851608ed87a708e0ed
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M tools/btattach.c

  Log Message:
  -----------
  btattach: Use _cleanup_fd_ to simplify error paths

Use _cleanup_fd_ and _steal_fd() to simplify error paths, and only
"steal" the file descriptor on success.


  Commit: f95b524e5a1d5a851ada7532160b80fa44dd4721
      https://github.com/bluez/bluez/commit/f95b524e5a1d5a851ada7532160b80fa44dd4721
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M mesh/net.c

  Log Message:
  -----------
  mesh: Remove unused but set variable

We played around with the bits, but didn't do anything with it.

mesh/net.c: In function ‘ack_received’:
mesh/net.c:1569:18: error: variable ‘ack_copy’ set but not used [-Werror=unused-but-set-variable=]
 1569 |         uint32_t ack_copy = ack_flag;
      |                  ^~~~~~~~


  Commit: 3940d9cf85a2a62ec2ad60ee50b2ac70b801cdf9
      https://github.com/bluez/bluez/commit/3940d9cf85a2a62ec2ad60ee50b2ac70b801cdf9
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M tools/mesh/mesh-db.c

  Log Message:
  -----------
  mesh: Fix str{r,}chr usage

Fix the code manipulating "const char *" return values from
json_object_to_json_string_ext() to modify it for printing, we're
not allowed to do that.

tools/mesh/mesh-db.c: In function ‘mesh_db_finish_export’:
tools/mesh/mesh-db.c:2598:13: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
 2598 |         pos = strrchr(hdr, '}');
      |             ^
tools/mesh/mesh-db.c:2604:13: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
 2604 |         pos = strrchr(hdr, '"');
      |             ^
tools/mesh/mesh-db.c:2613:13: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
 2613 |         pos = strchr(str, '{');
      |             ^


  Commit: 7b2b51ac6f6482e531dd23af7c6761f8c786cd13
      https://github.com/bluez/bluez/commit/7b2b51ac6f6482e531dd23af7c6761f8c786cd13
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M mesh/util.c

  Log Message:
  -----------
  mesh: Fix const qualifier dropping when using strchr()

strchr() with a const string returns a const string, we don't change
that string or "next", so make both const and get rid of the warning.

mesh/util.c: In function ‘create_dir’:
mesh/util.c:108:14: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
  108 |         prev = strchr(dir_name, '/');
      |              ^


  Commit: ec223f0782ef1265823b5233fccea0f3f552bab0
      https://github.com/bluez/bluez/commit/ec223f0782ef1265823b5233fccea0f3f552bab0
  Author: Pauli Virtanen <pav@iki.fi>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M src/adapter.c

  Log Message:
  -----------
  adapter: add BCAA UUID also when seen device is not discoverable

BAP v1.0.2 Sec 6.4 specifies Broadcast discovery uses observation
procedure (Core Vol 3 Part C Sec 9.1.2) which makes no reference to
device discoverability state.

However, if remote device does:

1. Send Advertising Data for some other UUID with General Discoverable
2. Send Advertising Data for BCAA UUID with no flags

then adapter.c:btd_adapter_device_found() creates device in step 1. but
in step 2. it ignores the BCAA UUID since the device exists but is not
discoverable; the monitoring=true special case applies only for
first-seen devices.  Consequently bap plugin fails to pick up the BCAA
stream.

This sequence was observed to be produced by BlueZ + btvirt.

Fix by monitoring also previously existing but currently non-connectable
devices with BCAA UUID.

Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/merge_requests/2812#note_3467783
Log:
--------------------------
@ MGMT Event: Device Found (0x0012) plen 17
        LE Address: 00:AA:01:00:00:42 (Intel Corporation)
        RSSI: invalid (0x7f)
        Flags: 0x00000000
        Data length: 3
        Data[3]:
        02 01 06                                         ...
        Flags: 0x06
          LE General Discoverable Mode
          BR/EDR Not Supported
...
@ MGMT Event: Device Found (0x0012) plen 39
        LE Address: 00:AA:01:00:00:42 (Intel Corporation)
        RSSI: invalid (0x7f)
        Flags: 0x00000004
          Not Connectable
        Data length: 25
        Data[25]:
        06 16 52 18 56 db 55 03 03 4e 18 0d 16 4e 18 00  ..R.V.U..N...N..
        ff 0f 0f 00 04 03 01 01 00                       .........
        Service Data: Broadcast Audio Announcement (0x1852)
        Broadcast ID: 5626710 (0x55db56)
        16-bit Service UUIDs (complete): 1 entry
          Audio Stream Control (0x184e)
        Service Data: Audio Stream Control (0x184e)
          Data[10]:
        00 ff 0f 0f 00 04 03 01 01 00
--------------------------


  Commit: 6ba04fad369f1dced3892944df6779c5f99b359c
      https://github.com/bluez/bluez/commit/6ba04fad369f1dced3892944df6779c5f99b359c
  Author: Frédéric Danis <frederic.danis@collabora.com>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M obexd/client/pbap.c

  Log Message:
  -----------
  pbap: Fix not checking Database Identifier length

Database Identifier is supposed to be 16 bytes values.

A paired Bluetooth device acting as a PBAP server can overflow the
heap in obexd by up to 239 bytes into adjacent allocations by returning
a DATABASEID_TAG application parameter with an oversized length.
With both length and content fully attacker-controlled, this enables
standard glibc heap exploitation primitives (tcache/fastbin poisoning)
leading to remote code execution in the obexd process.


Compare: https://github.com/bluez/bluez/compare/7cd27f4f66aa...6ba04fad369f

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-12 19:24 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1093372
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-12 19:24 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1093117
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* [bluez/bluez]
From: BluezTestBot @ 2026-05-12 19:24 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/1091796
  Home:   https://github.com/bluez/bluez

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* Re: [BlueZ v3 0/6] Add helper for "cleanup" variable attribute
From: Luiz Augusto von Dentz @ 2026-05-12 19:38 UTC (permalink / raw)
  To: patchwork-bot+bluetooth; +Cc: Bastien Nocera, linux-bluetooth
In-Reply-To: <177861361154.3045511.1045324340041670862.git-patchwork-notify@kernel.org>

Hi Bastien,

On Tue, May 12, 2026 at 3:21 PM <patchwork-bot+bluetooth@kernel.org> wrote:
>
> Hello:
>
> This series was applied to bluetooth/bluez.git (master)
> by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
>
> On Mon, 11 May 2026 15:18:03 +0200 you wrote:
> > As discussed in:
> > https://lore.kernel.org/linux-bluetooth/ed949f2550f79a4bef19bd482bf8b069ad5b7e0c.camel@hadess.net/
> >
> > Implement a cleanup helper.
> >
> > The MIN/MAX fix is here because it touches the same hunk in src/main.c
> > as the other patches. Feel free to pick it up straight away while the
> > rest is discussed.
> >
> > [...]
>
> Here is the summary with links:
>   - [BlueZ,v3,1/6] all: Remove more unneeded MIN/MAX macro definition
>     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ca2b39b0c08e
>   - [BlueZ,v3,2/6] shared/util: Add helper for "cleanup" variable attribute
>     (no matching commit)
>   - [BlueZ,v3,3/6] doc: Recommend using _cleanup_ and friends
>     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=9ba6c13df5fb
>   - [BlueZ,v3,4/6] main: Use _cleanup_() to simplify configuration parsing
>     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=140e3569295c
>   - [BlueZ,v3,5/6] client: Use _cleanup_fd_ to simplify urandom access
>     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e33f5027b898
>   - [BlueZ,v3,6/6] btattach: Use _cleanup_fd_ to simplify error paths
>     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=02aa9a8cfe6a
>
> You are awesome, thank you!
> --
> Deet-doot-dot, I am a bot.
> https://korg.docs.kernel.org/patchwork/pwbot.html

We will probably need to revert the cleanup changes, they are causing
crashes and other problems when run under Valgrind.

bluetoothd[941151]: src/main.c:parse_config() parsing src/main.conf
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4003098: parse_config_hex (main.c:961)
==941151==    by 0x4003098: parse_general (main.c:1058)
==941151==    by 0x4003098: parse_config (main.c:1341)
==941151==    by 0x4003098: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40F17EE: parse_config_int (main.c:467)
==941151==    by 0x40F1ECD: parse_config_u32.constprop.0.isra.0 (main.c:848)
==941151==    by 0x40030BD: parse_general (bluetooth.c:4925)
==941151==    by 0x40030BD: parse_config (main.c:1341)
==941151==    by 0x40030BD: main (main.c:1616)
==941151==  Address 0x1fff000050 is on thread 1's stack
==941151==  in frame #2, created by parse_config_int (main.c:465)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4004C89: parse_device_id (main.c:974)
==941151==    by 0x4004C89: parse_general (main.c:1067)
==941151==    by 0x4004C89: parse_config (main.c:1341)
==941151==    by 0x4004C89: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
bluetoothd[941151]: src/main.c:parse_config_string() General.ControllerMode = le
bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
bluetoothd[941151]: ++++++++ backtrace ++++++++
bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
bluetoothd[941151]: #2  g_logv+0x247
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
bluetoothd[941151]: #3  g_log+0x93
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
bluetoothd[941151]: #4  parse_config_string+0x60 (src/main.c:208) [0x40f1400]
bluetoothd[941151]: #5  main+0x4a2 (src/main.c:988) [0x4003262]
bluetoothd[941151]: #6  __libc_start_call_main+0x75
(/usr/lib64/libc.so.6) [0x4f90575]
bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
(/usr/lib64/libc.so.6) [0x4f90628]
bluetoothd[941151]: #8  _start+0x25
(/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
bluetoothd[941151]: +++++++++++++++++++++++++++
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4003311: parse_ctrl_mode (bluetooth.c:5033)
==941151==    by 0x4003311: parse_general (main.c:1074)
==941151==    by 0x4003311: parse_config (main.c:1341)
==941151==    by 0x4003311: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (bluetooth.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40F17EE: parse_config_int (main.c:467)
==941151==    by 0x40F20C2: parse_config_u16.isra.0 (main.c:863)
==941151==    by 0x4003349: parse_general (bluetooth.c:2985)
==941151==    by 0x4003349: parse_config (main.c:1341)
==941151==    by 0x4003349: main (main.c:1616)
==941151==  Address 0x1fff000050 is on thread 1's stack
==941151==  in frame #2, created by parse_config_int (main.c:465)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4004F55: parse_multi_profile (main.c:996)
==941151==    by 0x4004F55: parse_general (main.c:1078)
==941151==    by 0x4004F55: parse_config (main.c:1341)
==941151==    by 0x4004F55: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40F15D4: parse_privacy (main.c:910)
==941151==    by 0x40033F9: parse_general (main.c:1081)
==941151==    by 0x40033F9: parse_config (main.c:1341)
==941151==    by 0x40033F9: main (main.c:1616)
==941151==  Address 0x1fff000098 is on thread 1's stack
==941151==  in frame #2, created by parse_privacy (main.c:909)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40047B5: parse_repairing (main.c:947)
==941151==    by 0x40047B5: parse_general (main.c:1082)
==941151==    by 0x40047B5: parse_config (main.c:1341)
==941151==    by 0x40047B5: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40049FF: parse_secure_conns (bluetooth.c:1597)
==941151==    by 0x40049FF: parse_general (main.c:1088)
==941151==    by 0x40049FF: parse_config (main.c:1341)
==941151==    by 0x40049FF: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (bluetooth.c:1570)
==941151==
bluetoothd[941151]: src/main.c:parse_config_bool() General.Experimental = true
bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
bluetoothd[941151]: ++++++++ backtrace ++++++++
bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
bluetoothd[941151]: #2  g_logv+0x247
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
bluetoothd[941151]: #3  g_log+0x93
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
bluetoothd[941151]: #4  parse_config_bool.isra.0+0x64 (src/main.c:208)
[0x40f1f64]
bluetoothd[941151]: #5  main+0x7c0 (src/main.c:1089) [0x4003580]
bluetoothd[941151]: #6  __libc_start_call_main+0x75
(/usr/lib64/libc.so.6) [0x4f90575]
bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
(/usr/lib64/libc.so.6) [0x4f90628]
bluetoothd[941151]: #8  _start+0x25
(/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
bluetoothd[941151]: +++++++++++++++++++++++++++
bluetoothd[941151]: src/main.c:parse_config_string()
General.KernelExperimental = 6fbaf188-05e0-496a-9885-d6ddfdb4e03e
bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
bluetoothd[941151]: ++++++++ backtrace ++++++++
bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
bluetoothd[941151]: #2  g_logv+0x247
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
bluetoothd[941151]: #3  g_log+0x93
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
bluetoothd[941151]: #4  parse_config_string+0x60 (src/main.c:208) [0x40f1400]
bluetoothd[941151]: #5  main+0x816 (src/main.c:1032) [0x40035d6]
bluetoothd[941151]: #6  __libc_start_call_main+0x75
(/usr/lib64/libc.so.6) [0x4f90575]
bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
(/usr/lib64/libc.so.6) [0x4f90628]
bluetoothd[941151]: #8  _start+0x25
(/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
bluetoothd[941151]: +++++++++++++++++++++++++++
bluetoothd[941151]: src/main.c:btd_parse_kernel_experimental()
6fbaf188-05e0-496a-9885-d6ddfdb4e03e
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4003607: parse_kernel_exp (main.c:1030)
==941151==    by 0x4003607: parse_general (main.c:1093)
==941151==    by 0x4003607: parse_config (main.c:1341)
==941151==    by 0x4003607: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40F17EE: parse_config_int (main.c:467)
==941151==    by 0x40F19B8: parse_mode_config (main.c:552)
==941151==    by 0x40036D5: parse_le_config (bluetooth.c:2879)
==941151==    by 0x40036D5: parse_config (main.c:1343)
==941151==    by 0x40036D5: main (main.c:1616)
==941151==  Address 0x1fff000020 is on thread 1's stack
==941151==  in frame #2, created by parse_config_int (main.c:465)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4004C4B: parse_gatt_cache (main.c:1103)
==941151==    by 0x4004C4B: parse_gatt (main.c:1171)
==941151==    by 0x4004C4B: parse_config (main.c:1344)
==941151==    by 0x4004C4B: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40F17EE: parse_config_int (main.c:467)
==941151==    by 0x40F2072: parse_config_u8.isra.0 (main.c:878)
==941151==    by 0x40037E5: parse_gatt (bluetooth.c:2847)
==941151==    by 0x40037E5: parse_config (main.c:1344)
==941151==    by 0x40037E5: main (main.c:1616)
==941151==  Address 0x1fff000050 is on thread 1's stack
==941151==  in frame #2, created by parse_config_int (main.c:465)
==941151==
bluetoothd[941151]: src/main.c:parse_config_string()
GATT.ExportClaimedServices = read-write
bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
bluetoothd[941151]: ++++++++ backtrace ++++++++
bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
bluetoothd[941151]: #2  g_logv+0x247
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
bluetoothd[941151]: #3  g_log+0x93
(/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
bluetoothd[941151]: #4  parse_config_string+0x60 (src/main.c:208) [0x40f1400]
bluetoothd[941151]: #5  main+0xae3 (src/main.c:1132) [0x40038a3]
bluetoothd[941151]: #6  __libc_start_call_main+0x75
(/usr/lib64/libc.so.6) [0x4f90575]
bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
(/usr/lib64/libc.so.6) [0x4f90628]
bluetoothd[941151]: #8  _start+0x25
(/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
bluetoothd[941151]: +++++++++++++++++++++++++++
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x400395E: parse_gatt_export (main.c:1129)
==941151==    by 0x400395E: parse_gatt (main.c:1178)
==941151==    by 0x400395E: parse_config (main.c:1344)
==941151==    by 0x400395E: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40040AD: parse_gatt_seclevel (main.c:1157)
==941151==    by 0x40040AD: parse_gatt (main.c:1179)
==941151==    by 0x40040AD: parse_config (main.c:1344)
==941151==    by 0x40040AD: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4004A1E: parse_csis_sirk (bluetooth.c:1593)
==941151==    by 0x4004A1E: parse_csis (main.c:1197)
==941151==    by 0x4004A1E: parse_config (main.c:1345)
==941151==    by 0x4004A1E: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (bluetooth.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4004A3D: parse_avdtp_session_mode (main.c:1276)
==941151==    by 0x4004A3D: parse_avdtp (main.c:1310)
==941151==    by 0x4004A3D: parse_config (main.c:1346)
==941151==    by 0x4004A3D: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4004A5C: parse_avdtp_stream_mode (main.c:1293)
==941151==    by 0x4004A5C: parse_avdtp (main.c:1311)
==941151==    by 0x4004A5C: parse_config (main.c:1346)
==941151==    by 0x4004A5C: main (main.c:1616)
==941151==  Address 0x1fff000100 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x4004417: parse_cs_role (bluetooth.c:943)
==941151==    by 0x4004417: parse_le_cs_config (main.c:1264)
==941151==    by 0x4004417: parse_config (main.c:1348)
==941151==    by 0x4004417: main (main.c:1616)
==941151==  Address 0x1fff0000f8 is on thread 1's stack
==941151==  in frame #2, created by main (bluetooth.c:1570)
==941151==
==941151== Invalid free() / delete / delete[] / realloc()
==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
==941151==    by 0x40044FB: parse_config_signed_int (main.c:501)
==941151==    by 0x40044FB: parse_le_cs_config (main.c:1269)
==941151==    by 0x40044FB: parse_config (main.c:1348)
==941151==    by 0x40044FB: main (main.c:1616)
==941151==  Address 0x1fff0000f8 is on thread 1's stack
==941151==  in frame #2, created by main (main.c:1570)
==941151==
-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH] Bluetooth: bnep: Fix UAF read of dev->name
From: Jann Horn @ 2026-05-12 20:15 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz
  Cc: linux-bluetooth, linux-kernel, stable, Jann Horn

bnep_add_connection() needs to keep holding the bnep_session_sem while
reading dev->name (just like bnep_get_connlist() does); otherwise the
bnep_session() thread can concurrently free the net_device, which can for
example be triggered by a concurrent bnep_del_connection().

(This UAF is fairly uninteresting from a security perspective;
calling bnep_add_connection() requires passing a capable(CAP_NET_ADMIN)
check. It also requires completely tearing down a netdev during a fairly
tight race window.)

Cc: stable@vger.kernel.org
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Jann Horn <jannh@google.com>
---
I have tested that this bug can lead to UAF by using KASAN and
introducing an artificial delay with mdelay().
---
 net/bluetooth/bnep/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 853c8d7644b5..0de5df690bd0 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -645,8 +645,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
 		goto failed;
 	}
 
-	up_write(&bnep_session_sem);
 	strcpy(req->device, dev->name);
+	up_write(&bnep_session_sem);
 	return 0;
 
 failed:

---
base-commit: 1d5dcaa3bd65f2e8c9baa14a393d3a2dc5db7524
change-id: 20260512-bnep-add-uaf-f730caec3b13

--  
Jann Horn <jannh@google.com>


^ permalink raw reply related

* Re: [BlueZ v3 0/6] Add helper for "cleanup" variable attribute
From: Bastien Nocera @ 2026-05-12 20:12 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZ+RZH25K0jhRsrTbYOZxQQeV9EvxYK907sgGW0Ot-mR3Q@mail.gmail.com>

On Tue, 2026-05-12 at 15:38 -0400, Luiz Augusto von Dentz wrote:
> Hi Bastien,
> 
> On Tue, May 12, 2026 at 3:21 PM <patchwork-bot+bluetooth@kernel.org>
> wrote:
> > 
> > Hello:
> > 
> > This series was applied to bluetooth/bluez.git (master)
> > by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
> > 
> > On Mon, 11 May 2026 15:18:03 +0200 you wrote:
> > > As discussed in:
> > > https://lore.kernel.org/linux-bluetooth/ed949f2550f79a4bef19bd482bf8b069ad5b7e0c.camel@hadess.net/
> > > 
> > > Implement a cleanup helper.
> > > 
> > > The MIN/MAX fix is here because it touches the same hunk in
> > > src/main.c
> > > as the other patches. Feel free to pick it up straight away while
> > > the
> > > rest is discussed.
> > > 
> > > [...]
> > 
> > Here is the summary with links:
> >   - [BlueZ,v3,1/6] all: Remove more unneeded MIN/MAX macro
> > definition
> >    
> > https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ca2b39b0c08e
> >   - [BlueZ,v3,2/6] shared/util: Add helper for "cleanup" variable
> > attribute
> >     (no matching commit)
> >   - [BlueZ,v3,3/6] doc: Recommend using _cleanup_ and friends
> >    
> > https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=9ba6c13df5fb
> >   - [BlueZ,v3,4/6] main: Use _cleanup_() to simplify configuration
> > parsing
> >    
> > https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=140e3569295c
> >   - [BlueZ,v3,5/6] client: Use _cleanup_fd_ to simplify urandom
> > access
> >    
> > https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e33f5027b898
> >   - [BlueZ,v3,6/6] btattach: Use _cleanup_fd_ to simplify error
> > paths
> >    
> > https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=02aa9a8cfe6a
> > 
> > You are awesome, thank you!
> > --
> > Deet-doot-dot, I am a bot.
> > https://korg.docs.kernel.org/patchwork/pwbot.html
> 
> We will probably need to revert the cleanup changes, they are causing
> crashes and other problems when run under Valgrind.

Please do, I've managed to reproduce some of the problems locally,
which I didn't see in my testing, even running under valgrind.

I'll send a v4 later.

Cheers

^ permalink raw reply

* Re: [BlueZ v3 0/6] Add helper for "cleanup" variable attribute
From: Pauli Virtanen @ 2026-05-12 20:40 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: Bastien Nocera, linux-bluetooth
In-Reply-To: <CABBYNZ+RZH25K0jhRsrTbYOZxQQeV9EvxYK907sgGW0Ot-mR3Q@mail.gmail.com>

ti, 2026-05-12 kello 15:38 -0400, Luiz Augusto von Dentz kirjoitti:
> Hi Bastien,
> 
> On Tue, May 12, 2026 at 3:21 PM <patchwork-bot+bluetooth@kernel.org> wrote:
> > 
> > Hello:
> > 
> > This series was applied to bluetooth/bluez.git (master)
> > by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
> > 
> > On Mon, 11 May 2026 15:18:03 +0200 you wrote:
> > > As discussed in:
> > > https://lore.kernel.org/linux-bluetooth/ed949f2550f79a4bef19bd482bf8b069ad5b7e0c.camel@hadess.net/
> > > 
> > > Implement a cleanup helper.
> > > 
> > > The MIN/MAX fix is here because it touches the same hunk in src/main.c
> > > as the other patches. Feel free to pick it up straight away while the
> > > rest is discussed.
> > > 
> > > [...]
> > 
> > Here is the summary with links:
> >   - [BlueZ,v3,1/6] all: Remove more unneeded MIN/MAX macro definition
> >     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=ca2b39b0c08e
> >   - [BlueZ,v3,2/6] shared/util: Add helper for "cleanup" variable attribute
> >     (no matching commit)
> >   - [BlueZ,v3,3/6] doc: Recommend using _cleanup_ and friends
> >     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=9ba6c13df5fb
> >   - [BlueZ,v3,4/6] main: Use _cleanup_() to simplify configuration parsing
> >     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=140e3569295c
> >   - [BlueZ,v3,5/6] client: Use _cleanup_fd_ to simplify urandom access
> >     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=e33f5027b898
> >   - [BlueZ,v3,6/6] btattach: Use _cleanup_fd_ to simplify error paths
> >     https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=02aa9a8cfe6a
> > 
> > You are awesome, thank you!
> > --
> > Deet-doot-dot, I am a bot.
> > https://korg.docs.kernel.org/patchwork/pwbot.html
> 
> We will probably need to revert the cleanup changes, they are causing
> crashes and other problems when run under Valgrind.
> 
> bluetoothd[941151]: src/main.c:parse_config() parsing src/main.conf
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4003098: parse_config_hex (main.c:961)
> ==941151==    by 0x4003098: parse_general (main.c:1058)
> ==941151==    by 0x4003098: parse_config (main.c:1341)
> ==941151==    by 0x4003098: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40F17EE: parse_config_int (main.c:467)
> ==941151==    by 0x40F1ECD: parse_config_u32.constprop.0.isra.0 (main.c:848)
> ==941151==    by 0x40030BD: parse_general (bluetooth.c:4925)
> ==941151==    by 0x40030BD: parse_config (main.c:1341)
> ==941151==    by 0x40030BD: main (main.c:1616)
> ==941151==  Address 0x1fff000050 is on thread 1's stack
> ==941151==  in frame #2, created by parse_config_int (main.c:465)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4004C89: parse_device_id (main.c:974)
> ==941151==    by 0x4004C89: parse_general (main.c:1067)
> ==941151==    by 0x4004C89: parse_config (main.c:1341)
> ==941151==    by 0x4004C89: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> bluetoothd[941151]: src/main.c:parse_config_string() General.ControllerMode = le
> bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
> bluetoothd[941151]: ++++++++ backtrace ++++++++
> bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
> bluetoothd[941151]: #2  g_logv+0x247
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
> bluetoothd[941151]: #3  g_log+0x93
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
> bluetoothd[941151]: #4  parse_config_string+0x60 (src/main.c:208) [0x40f1400]
> bluetoothd[941151]: #5  main+0x4a2 (src/main.c:988) [0x4003262]
> bluetoothd[941151]: #6  __libc_start_call_main+0x75
> (/usr/lib64/libc.so.6) [0x4f90575]
> bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
> (/usr/lib64/libc.so.6) [0x4f90628]
> bluetoothd[941151]: #8  _start+0x25
> (/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
> bluetoothd[941151]: +++++++++++++++++++++++++++
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4003311: parse_ctrl_mode (bluetooth.c:5033)
> ==941151==    by 0x4003311: parse_general (main.c:1074)
> ==941151==    by 0x4003311: parse_config (main.c:1341)
> ==941151==    by 0x4003311: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (bluetooth.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40F17EE: parse_config_int (main.c:467)
> ==941151==    by 0x40F20C2: parse_config_u16.isra.0 (main.c:863)
> ==941151==    by 0x4003349: parse_general (bluetooth.c:2985)
> ==941151==    by 0x4003349: parse_config (main.c:1341)
> ==941151==    by 0x4003349: main (main.c:1616)
> ==941151==  Address 0x1fff000050 is on thread 1's stack
> ==941151==  in frame #2, created by parse_config_int (main.c:465)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4004F55: parse_multi_profile (main.c:996)
> ==941151==    by 0x4004F55: parse_general (main.c:1078)
> ==941151==    by 0x4004F55: parse_config (main.c:1341)
> ==941151==    by 0x4004F55: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40F15D4: parse_privacy (main.c:910)
> ==941151==    by 0x40033F9: parse_general (main.c:1081)
> ==941151==    by 0x40033F9: parse_config (main.c:1341)
> ==941151==    by 0x40033F9: main (main.c:1616)
> ==941151==  Address 0x1fff000098 is on thread 1's stack
> ==941151==  in frame #2, created by parse_privacy (main.c:909)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40047B5: parse_repairing (main.c:947)
> ==941151==    by 0x40047B5: parse_general (main.c:1082)
> ==941151==    by 0x40047B5: parse_config (main.c:1341)
> ==941151==    by 0x40047B5: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40049FF: parse_secure_conns (bluetooth.c:1597)
> ==941151==    by 0x40049FF: parse_general (main.c:1088)
> ==941151==    by 0x40049FF: parse_config (main.c:1341)
> ==941151==    by 0x40049FF: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (bluetooth.c:1570)
> ==941151==
> bluetoothd[941151]: src/main.c:parse_config_bool() General.Experimental = true
> bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
> bluetoothd[941151]: ++++++++ backtrace ++++++++
> bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
> bluetoothd[941151]: #2  g_logv+0x247
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
> bluetoothd[941151]: #3  g_log+0x93
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
> bluetoothd[941151]: #4  parse_config_bool.isra.0+0x64 (src/main.c:208)
> [0x40f1f64]
> bluetoothd[941151]: #5  main+0x7c0 (src/main.c:1089) [0x4003580]
> bluetoothd[941151]: #6  __libc_start_call_main+0x75
> (/usr/lib64/libc.so.6) [0x4f90575]
> bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
> (/usr/lib64/libc.so.6) [0x4f90628]
> bluetoothd[941151]: #8  _start+0x25
> (/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
> bluetoothd[941151]: +++++++++++++++++++++++++++
> bluetoothd[941151]: src/main.c:parse_config_string()
> General.KernelExperimental = 6fbaf188-05e0-496a-9885-d6ddfdb4e03e
> bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
> bluetoothd[941151]: ++++++++ backtrace ++++++++
> bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
> bluetoothd[941151]: #2  g_logv+0x247
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
> bluetoothd[941151]: #3  g_log+0x93
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
> bluetoothd[941151]: #4  parse_config_string+0x60 (src/main.c:208) [0x40f1400]
> bluetoothd[941151]: #5  main+0x816 (src/main.c:1032) [0x40035d6]
> bluetoothd[941151]: #6  __libc_start_call_main+0x75
> (/usr/lib64/libc.so.6) [0x4f90575]
> bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
> (/usr/lib64/libc.so.6) [0x4f90628]
> bluetoothd[941151]: #8  _start+0x25
> (/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
> bluetoothd[941151]: +++++++++++++++++++++++++++
> bluetoothd[941151]: src/main.c:btd_parse_kernel_experimental()
> 6fbaf188-05e0-496a-9885-d6ddfdb4e03e
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4003607: parse_kernel_exp (main.c:1030)
> ==941151==    by 0x4003607: parse_general (main.c:1093)
> ==941151==    by 0x4003607: parse_config (main.c:1341)
> ==941151==    by 0x4003607: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40F17EE: parse_config_int (main.c:467)
> ==941151==    by 0x40F19B8: parse_mode_config (main.c:552)
> ==941151==    by 0x40036D5: parse_le_config (bluetooth.c:2879)
> ==941151==    by 0x40036D5: parse_config (main.c:1343)
> ==941151==    by 0x40036D5: main (main.c:1616)
> ==941151==  Address 0x1fff000020 is on thread 1's stack
> ==941151==  in frame #2, created by parse_config_int (main.c:465)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4004C4B: parse_gatt_cache (main.c:1103)
> ==941151==    by 0x4004C4B: parse_gatt (main.c:1171)
> ==941151==    by 0x4004C4B: parse_config (main.c:1344)
> ==941151==    by 0x4004C4B: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40F17EE: parse_config_int (main.c:467)
> ==941151==    by 0x40F2072: parse_config_u8.isra.0 (main.c:878)
> ==941151==    by 0x40037E5: parse_gatt (bluetooth.c:2847)
> ==941151==    by 0x40037E5: parse_config (main.c:1344)
> ==941151==    by 0x40037E5: main (main.c:1616)
> ==941151==  Address 0x1fff000050 is on thread 1's stack
> ==941151==  in frame #2, created by parse_config_int (main.c:465)
> ==941151==
> bluetoothd[941151]: src/main.c:parse_config_string()
> GATT.ExportClaimedServices = read-write
> bluetoothd[941151]: GLib: g_error_free: assertion 'error != NULL' failed
> bluetoothd[941151]: ++++++++ backtrace ++++++++
> bluetoothd[941151]: #1  log_handler+0x4e (src/main.c:1418) [0x40f0ffe]
> bluetoothd[941151]: #2  g_logv+0x247
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5477]
> bluetoothd[941151]: #3  g_log+0x93
> (/usr/lib64/libglib-2.0.so.0.8400.4) [0x4cc5803]
> bluetoothd[941151]: #4  parse_config_string+0x60 (src/main.c:208) [0x40f1400]
> bluetoothd[941151]: #5  main+0xae3 (src/main.c:1132) [0x40038a3]
> bluetoothd[941151]: #6  __libc_start_call_main+0x75
> (/usr/lib64/libc.so.6) [0x4f90575]
> bluetoothd[941151]: #7  __libc_start_main@@GLIBC_2.34+0x88
> (/usr/lib64/libc.so.6) [0x4f90628]
> bluetoothd[941151]: #8  _start+0x25
> (/home/vudentz/git/bluez/src/bluetoothd) [0x40054c5]
> bluetoothd[941151]: +++++++++++++++++++++++++++
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x400395E: parse_gatt_export (main.c:1129)
> ==941151==    by 0x400395E: parse_gatt (main.c:1178)
> ==941151==    by 0x400395E: parse_config (main.c:1344)
> ==941151==    by 0x400395E: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40040AD: parse_gatt_seclevel (main.c:1157)
> ==941151==    by 0x40040AD: parse_gatt (main.c:1179)
> ==941151==    by 0x40040AD: parse_config (main.c:1344)
> ==941151==    by 0x40040AD: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4004A1E: parse_csis_sirk (bluetooth.c:1593)
> ==941151==    by 0x4004A1E: parse_csis (main.c:1197)
> ==941151==    by 0x4004A1E: parse_config (main.c:1345)
> ==941151==    by 0x4004A1E: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (bluetooth.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4004A3D: parse_avdtp_session_mode (main.c:1276)
> ==941151==    by 0x4004A3D: parse_avdtp (main.c:1310)
> ==941151==    by 0x4004A3D: parse_config (main.c:1346)
> ==941151==    by 0x4004A3D: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4004A5C: parse_avdtp_stream_mode (main.c:1293)
> ==941151==    by 0x4004A5C: parse_avdtp (main.c:1311)
> ==941151==    by 0x4004A5C: parse_config (main.c:1346)
> ==941151==    by 0x4004A5C: main (main.c:1616)
> ==941151==  Address 0x1fff000100 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x4004417: parse_cs_role (bluetooth.c:943)
> ==941151==    by 0x4004417: parse_le_cs_config (main.c:1264)
> ==941151==    by 0x4004417: parse_config (main.c:1348)
> ==941151==    by 0x4004417: main (main.c:1616)
> ==941151==  Address 0x1fff0000f8 is on thread 1's stack
> ==941151==  in frame #2, created by main (bluetooth.c:1570)
> ==941151==
> ==941151== Invalid free() / delete / delete[] / realloc()
> ==941151==    at 0x4BADE43: free (vg_replace_malloc.c:990)
> ==941151==    by 0x4CC0444: g_free (in /usr/lib64/libglib-2.0.so.0.8400.4)
> ==941151==    by 0x40044FB: parse_config_signed_int (main.c:501)
> ==941151==    by 0x40044FB: parse_le_cs_config (main.c:1269)
> ==941151==    by 0x40044FB: parse_config (main.c:1348)
> ==941151==    by 0x40044FB: main (main.c:1616)
> ==941151==  Address 0x1fff0000f8 is on thread 1's stack
> ==941151==  in frame #2, created by main (main.c:1570)
> ==941151==

I think it needed something like the below.

I think it would be better to have _steal_() and _steal_fd_() be macros
so that compiler can check the types so you can't mistake
_steal_(keyfile) and _steal_(&keyfile)

https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/spa/include/spa/utils/cleanup.h

Not sure what can be done about the _cleanup_(g_free) char *str --- it
would be great if this generated compiler warning/error but it looks
like it didn't, so maybe this macro should be private so you're forced
to declare the CLEANUP_FREEFUNC always.


diff --git a/src/main.c b/src/main.c
index 9053e74aa..9d1074c11 100644
--- a/src/main.c
+++ b/src/main.c
@@ -205,8 +205,20 @@ static const struct group_table {
 	{ }
 };
 
-CLEANUP_FREEFUNC(GError, g_error_free);
-CLEANUP_FREEFUNC(GKeyFile, g_key_file_free);
+static void cleanup_g_error(GError *err)
+{
+	if (err)
+		g_error_free(err);
+}
+
+static void cleanup_g_key_file(GKeyFile *keyfile)
+{
+	if (keyfile)
+		g_key_file_free(keyfile);
+}
+
+CLEANUP_FREEFUNC(GError, cleanup_g_error);
+CLEANUP_FREEFUNC(GKeyFile, cleanup_g_key_file);
 
 static int8_t check_sirk_alpha_numeric(char *str)
 {
@@ -291,7 +303,7 @@ static GKeyFile *load_config(const char *name)
 		return NULL;
 	}
 
-	return _steal_(keyfile);
+	return _steal_(&keyfile);
 }
 
 static void parse_did(const char *did)
@@ -457,12 +469,19 @@ static bool parse_config_string(GKeyFile *config,
const char *group,
 	return true;
 }
 
+static inline void cleanup_g_free(void *p)
+{
+	g_free(*(void **) p);
+}
+
+#define _cleanup_g_free_ _cleanup_(cleanup_g_free)
+
 static bool parse_config_int(GKeyFile *config, const char *group,
 					const char *key, int *val,
 					size_t min, size_t max)
 {
 	size_t tmp;
-	_cleanup_(g_free) char *str = NULL;
+	_cleanup_g_free_ char *str = NULL;
 	char *endptr = NULL;
 
 	if (!parse_config_string(config, group, key, &str))

and so on for the rest of _cleanup_(g_free)

-- 
Pauli Virtanen

^ permalink raw reply related

* [bluez/bluez] 4ed84c: mesh: Remove unused but set variable
From: fdanis-oss @ 2026-05-12 20:54 UTC (permalink / raw)
  To: linux-bluetooth

  Branch: refs/heads/master
  Home:   https://github.com/bluez/bluez
  Commit: 4ed84c4132f42c6e61934ce7f6bc29433c3e000f
      https://github.com/bluez/bluez/commit/4ed84c4132f42c6e61934ce7f6bc29433c3e000f
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M mesh/net.c

  Log Message:
  -----------
  mesh: Remove unused but set variable

We played around with the bits, but didn't do anything with it.

mesh/net.c: In function ‘ack_received’:
mesh/net.c:1569:18: error: variable ‘ack_copy’ set but not used [-Werror=unused-but-set-variable=]
 1569 |         uint32_t ack_copy = ack_flag;
      |                  ^~~~~~~~


  Commit: a225faba50d1224b1191c84198fefa4f7053bb6c
      https://github.com/bluez/bluez/commit/a225faba50d1224b1191c84198fefa4f7053bb6c
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M tools/mesh/mesh-db.c

  Log Message:
  -----------
  mesh: Fix str{r,}chr usage

Fix the code manipulating "const char *" return values from
json_object_to_json_string_ext() to modify it for printing, we're
not allowed to do that.

tools/mesh/mesh-db.c: In function ‘mesh_db_finish_export’:
tools/mesh/mesh-db.c:2598:13: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
 2598 |         pos = strrchr(hdr, '}');
      |             ^
tools/mesh/mesh-db.c:2604:13: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
 2604 |         pos = strrchr(hdr, '"');
      |             ^
tools/mesh/mesh-db.c:2613:13: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
 2613 |         pos = strchr(str, '{');
      |             ^


  Commit: 28c9f959bb3be8e311b34a6c08bd95045dabd7bf
      https://github.com/bluez/bluez/commit/28c9f959bb3be8e311b34a6c08bd95045dabd7bf
  Author: Bastien Nocera <hadess@hadess.net>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M mesh/util.c

  Log Message:
  -----------
  mesh: Fix const qualifier dropping when using strchr()

strchr() with a const string returns a const string, we don't change
that string or "next", so make both const and get rid of the warning.

mesh/util.c: In function ‘create_dir’:
mesh/util.c:108:14: error: assignment discards ‘const’ qualifier from pointer target type [-Werror=discarded-qualifiers]
  108 |         prev = strchr(dir_name, '/');
      |              ^


  Commit: 31625e481b081efb2d654d401eca2abf1274d0ed
      https://github.com/bluez/bluez/commit/31625e481b081efb2d654d401eca2abf1274d0ed
  Author: Pauli Virtanen <pav@iki.fi>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M src/adapter.c

  Log Message:
  -----------
  adapter: add BCAA UUID also when seen device is not discoverable

BAP v1.0.2 Sec 6.4 specifies Broadcast discovery uses observation
procedure (Core Vol 3 Part C Sec 9.1.2) which makes no reference to
device discoverability state.

However, if remote device does:

1. Send Advertising Data for some other UUID with General Discoverable
2. Send Advertising Data for BCAA UUID with no flags

then adapter.c:btd_adapter_device_found() creates device in step 1. but
in step 2. it ignores the BCAA UUID since the device exists but is not
discoverable; the monitoring=true special case applies only for
first-seen devices.  Consequently bap plugin fails to pick up the BCAA
stream.

This sequence was observed to be produced by BlueZ + btvirt.

Fix by monitoring also previously existing but currently non-connectable
devices with BCAA UUID.

Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/merge_requests/2812#note_3467783
Log:
--------------------------
@ MGMT Event: Device Found (0x0012) plen 17
        LE Address: 00:AA:01:00:00:42 (Intel Corporation)
        RSSI: invalid (0x7f)
        Flags: 0x00000000
        Data length: 3
        Data[3]:
        02 01 06                                         ...
        Flags: 0x06
          LE General Discoverable Mode
          BR/EDR Not Supported
...
@ MGMT Event: Device Found (0x0012) plen 39
        LE Address: 00:AA:01:00:00:42 (Intel Corporation)
        RSSI: invalid (0x7f)
        Flags: 0x00000004
          Not Connectable
        Data length: 25
        Data[25]:
        06 16 52 18 56 db 55 03 03 4e 18 0d 16 4e 18 00  ..R.V.U..N...N..
        ff 0f 0f 00 04 03 01 01 00                       .........
        Service Data: Broadcast Audio Announcement (0x1852)
        Broadcast ID: 5626710 (0x55db56)
        16-bit Service UUIDs (complete): 1 entry
          Audio Stream Control (0x184e)
        Service Data: Audio Stream Control (0x184e)
          Data[10]:
        00 ff 0f 0f 00 04 03 01 01 00
--------------------------


  Commit: ee4a4775bc4f8348e2a860dc44bcdd7570279908
      https://github.com/bluez/bluez/commit/ee4a4775bc4f8348e2a860dc44bcdd7570279908
  Author: Frédéric Danis <frederic.danis@collabora.com>
  Date:   2026-05-12 (Tue, 12 May 2026)

  Changed paths:
    M obexd/client/pbap.c

  Log Message:
  -----------
  pbap: Fix not checking Database Identifier length

Database Identifier is supposed to be 16 bytes values.

A paired Bluetooth device acting as a PBAP server can overflow the
heap in obexd by up to 239 bytes into adjacent allocations by returning
a DATABASEID_TAG application parameter with an oversized length.
With both length and content fully attacker-controlled, this enables
standard glibc heap exploitation primitives (tcache/fastbin poisoning)
leading to remote code execution in the obexd process.


Compare: https://github.com/bluez/bluez/compare/6ba04fad369f...ee4a4775bc4f

To unsubscribe from these emails, change your notification settings at https://github.com/bluez/bluez/settings/notifications

^ permalink raw reply

* RE: Bluetooth: bnep: Fix UAF read of dev->name
From: bluez.test.bot @ 2026-05-12 21:23 UTC (permalink / raw)
  To: linux-bluetooth, jannh
In-Reply-To: <20260512-bnep-add-uaf-v1-1-f62ff8f61d50@google.com>

[-- Attachment #1: Type: text/plain, Size: 1470 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=1093767

---Test result---

Test Summary:
CheckPatch                    PASS      0.54 seconds
GitLint                       FAIL      0.21 seconds
SubjectPrefix                 PASS      0.07 seconds
BuildKernel                   PASS      26.75 seconds
CheckAllWarning               PASS      29.78 seconds
CheckSparse                   PASS      27.99 seconds
BuildKernel32                 PASS      26.10 seconds
TestRunnerSetup               PASS      579.08 seconds
TestRunner_bnep-tester        PASS      19.09 seconds
IncrementalBuild              PASS      24.48 seconds

Details
##############################
Test: GitLint - FAIL
Desc: Run gitlint
Output:
Bluetooth: bnep: Fix UAF read of dev->name

WARNING: I3 - ignore-body-lines: gitlint will be switching from using Python regex 'match' (match beginning) to 'search' (match anywhere) semantics. Please review your ignore-body-lines.regex option accordingly. To remove this warning, set general.regex-style-search=True. More details: https://jorisroovers.github.io/gitlint/configuration/#regex-style-search
27: B2 Line has trailing whitespace: "--  "


https://github.com/bluez/bluetooth-next/pull/179

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH v4] Bluetooth: Add Synaptics 4384 Chip Support
From: kaihsin Chung @ 2026-05-13  2:20 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: marcel, luiz.von.dentz, linux-kernel, Kaihsin Chung
In-Reply-To: <20260408083217.1915419-1-kaihsin.chung@synaptics.com>

From: Kaihsin Chung <kaihsin.chung@synaptics.com>

Add BCM4384A0 and BCM4384B0 identifiers to the Broadcom Bluetooth
subversion table and add device tree matching for brcm,bcm4384-bt.

Signed-off-by: kaihsin Chung <kaihsin.chung@synaptics.com>
---
 drivers/bluetooth/btbcm.c   | 6 +++++-
 drivers/bluetooth/hci_bcm.c | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c
index f9a7c790d7e2..1164cca40324 100644
--- a/drivers/bluetooth/btbcm.c
+++ b/drivers/bluetooth/btbcm.c
@@ -31,6 +31,7 @@
 #define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}})
 #define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}})
 #define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}})
+#define BDADDR_BCM4384B0 (&(bdaddr_t) {{0x93, 0x76, 0x00, 0xb0, 0x84, 0x43}})
 
 #define BCM_FW_NAME_LEN			64
 #define BCM_FW_NAME_COUNT_MAX		4
@@ -130,7 +131,8 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
 	    !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) ||
 	    !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) ||
 	    !bacmp(&bda->bdaddr, BDADDR_BCM43430A1) ||
-	    !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) {
+	    !bacmp(&bda->bdaddr, BDADDR_BCM43341B) ||
+	    !bacmp(&bda->bdaddr, BDADDR_BCM4384B0)) {
 		/* Try falling back to BDADDR EFI variable */
 		if (btbcm_set_bdaddr_from_efi(hdev) != 0) {
 			bt_dev_info(hdev, "BCM: Using default device address (%pMR)",
@@ -515,6 +517,8 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
 	{ 0x4106, "BCM4335A0"	},	/* 002.001.006 */
 	{ 0x410c, "BCM43430B0"	},	/* 002.001.012 */
 	{ 0x2119, "BCM4373A0"	},	/* 001.001.025 */
+	{ 0x2128, "BCM4384A0" },/* 001.001.040 */
+	{ 0x4119, "BCM4384B0"},/* 002.001.025 */
 	{ }
 };
 
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 874d23089b39..783346a4a59b 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -1609,6 +1609,7 @@ static const struct of_device_id bcm_bluetooth_of_match[] = {
 	{ .compatible = "brcm,bcm4335a0" },
 	{ .compatible = "cypress,cyw4373a0-bt", .data = &cyw4373a0_device_data },
 	{ .compatible = "infineon,cyw55572-bt", .data = &cyw55572_device_data },
+	{ .compatible = "brcm,bcm4384-bt" },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, bcm_bluetooth_of_match);
-- 
2.43.0


^ permalink raw reply related

* BUG: General Protection Fault in h5_recv due to TTY line discipline race condition (TIOCSTI)
From: 王明煜 @ 2026-05-13  2:54 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz
  Cc: linux-bluetooth, linux-kernel, linux-serial


Hi all,

We have discovered a severe NULL pointer dereference and subsequent General Protection Fault in `h5_recv()` within `drivers/bluetooth/hci_h5.c`. This crash is triggered by a race condition between the initialization of the HCI UART line discipline and concurrent data injection via the `TIOCSTI` ioctl.

This issue was found during fuzzing with a custom LLM-assisted device modeling framework.

### Crash Trace (KASAN)

Oops: general protection fault, probably for non-canonical address 0xdffffc000000005f: 0000 [#1] SMP KASAN PTI
KASAN: null-ptr-deref in range [0x00000000000002f8-0x00000000000002ff]
CPU: 3 UID: 0 PID: 75833 Comm: syz.0.5605 Not tainted 6.18.0 #1 PREEMPT(full) 
RIP: 0010:h5_recv+0xfc/0x8f0 drivers/bluetooth/hci_h5.c:572
...
Call Trace:
 <TASK>
 hci_uart_tty_receive+0x25b/0x800 drivers/bluetooth/hci_ldisc.c:627
 tiocsti drivers/tty/tty_io.c:2290 [inline]
 tty_ioctl+0x502/0x1690 drivers/tty/tty_io.c:2706
 __x64_sys_ioctl+0x18f/0x210 fs/ioctl.c:583
 do_syscall_64+0xcb/0xfa0 arch/x86/entry/syscall_64.c:94
...

### Vulnerability Analysis

The crash occurs due to an architectural race window during the line discipline setup:

1. Thread A executes `ioctl(HCIUARTSETPROTO)` to set the line discipline to HCI_UART_H5. The kernel sets the `HCI_UART_PROTO_INIT` bit in `hu->flags` and proceeds to call `hci_uart_register_dev()`, which eventually invokes `h5_open()`.
2. Before `h5_open()` finishes executing and allocates memory for `hu->priv` (i.e., before `hu->priv = h5;` is executed), Thread B concurrently executes `ioctl(TIOCSTI)`.
3. The `TIOCSTI` command forces data into the TTY receive path, calling `hci_uart_tty_receive()`.
4. Inside `hci_uart_tty_receive()`, the condition `!test_bit(HCI_UART_PROTO_INIT, &hu->flags)` evaluates to FALSE (because Thread A set it), allowing the execution to proceed without dropping the data.
5. The execution flows into `hu->proto->recv()` -> `h5_recv()`.
6. `h5_recv()` blindly dereferences `hu->priv` (which is still NULL), leading to the GPF when accessing `h5->rx_pending` on line 572: `BT_DBG("... %zu ...", ..., h5->rx_pending, ...);`.

### Proposed Fix Direction

While adding a simple `if (!h5) return 0;` at the beginning of `h5_recv()` prevents the crash, it seems the root cause lies in the permissiveness of the `HCI_UART_PROTO_INIT` state in `hci_uart_tty_receive()`, or the lack of proper synchronization between the `open` callback and the `recv` path during initialization.

Since we are not entirely familiar with the specific handshake requirements of the H5 protocol during the `PROTO_INIT` phase, we are reporting this vulnerability here rather than submitting a potentially flawed patch.

Please let us know if you need more information or the full reproducer.

Reported-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>

Best regards,
Mingyu Wang

^ permalink raw reply

* [PATCH] Bluetooth: bnep: reject short frames before parsing
From: Zhang Cen @ 2026-05-13  3:12 UTC (permalink / raw)
  To: Marcel Holtmann, Luiz Augusto von Dentz
  Cc: linux-bluetooth, linux-kernel, zerocling0077, 2045gemini,
	Zhang Cen

An L2CAP peer can deliver an empty BNEP payload or a payload that contains
only the outer type byte. bnep_rx_frame() currently dereferences the type
byte and, for control traffic, the control opcode before it proves that
those bytes exist in the skb. The setup-connection control path can also
read the setup size byte before it is present. bnep_rx_control() has the
same problem when it is asked to parse an empty control payload.

Reject empty skbs before reading the outer type byte, require a control
opcode before parsing BNEP_CONTROL, require the setup size byte before
using it, and make bnep_rx_control() fail zero-length control payloads.

Sanitizer validation reported:
KASAN slab-out-of-bounds in bnep_rx_frame()
Read of size 1
Call trace:
  dump_stack_lvl() (?:?)
  print_address_description() (mm/kasan/report.c:373)
  bnep_rx_frame() (net/bluetooth/bnep/core.c:306)
  print_report() (?:?)
  __virt_addr_valid() (?:?)
  srso_alias_return_thunk() (arch/x86/include/asm/nospec-branch.h:375)
  kasan_addr_to_slab() (mm/kasan/common.c:45)
  kasan_report() (?:?)
  process_one_work() (kernel/workqueue.c:3200)
  worker_thread() (?:?)
  __kthread_parkme() (kernel/kthread.c:259)
  kthread() (?:?)
  _raw_spin_unlock_irq() (kernel/locking/spinlock.c:204)
  ret_from_fork() (?:?)
  __switch_to() (?:?)
  ret_from_fork_asm() (?:?)
  kasan_save_stack() (mm/kasan/common.c:52)
  kasan_save_track() (mm/kasan/common.c:74)
  __kasan_kmalloc() (?:?)
  vpanic() (kernel/panic.c:576)
  panic() (?:?)
  preempt_schedule_common() (kernel/sched/core.c:7352)
  preempt_schedule_thunk() (?:?)
  end_report() (mm/kasan/report.c:219)

Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>

---
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index d44987d4515c..f5070bbd6b57 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -208,9 +208,14 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
 
 static int bnep_rx_control(struct bnep_session *s, void *data, int len)
 {
-	u8  cmd = *(u8 *)data;
+	u8  cmd;
 	int err = 0;
 
+	if (len < 1)
+		return -EILSEQ;
+
+	cmd = *(u8 *)data;
+
 	data++;
 	len--;
 
@@ -303,14 +308,21 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 
 	dev->stats.rx_bytes += skb->len;
 
+	if (skb->len < 1)
+		goto badframe;
+
 	type = *(u8 *) skb->data;
 	skb_pull(skb, 1);
-	ctrl_type = *(u8 *)skb->data;
 
 	if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen))
 		goto badframe;
 
 	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
+		if (skb->len < 1)
+			goto badframe;
+
+		ctrl_type = *(u8 *)skb->data;
+
 		if (bnep_rx_control(s, skb->data, skb->len) < 0) {
 			dev->stats.tx_errors++;
 			kfree_skb(skb);
@@ -326,6 +338,9 @@ static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
 		switch (ctrl_type) {
 		case BNEP_SETUP_CONN_REQ:
 			/* Pull: ctrl type (1 b), len (1 b), data (len bytes) */
+			if (skb->len < 2)
+				goto badframe;
+
 			if (!skb_pull(skb, 2 + *(u8 *)(skb->data + 1) * 2))
 				goto badframe;
 			break;

^ permalink raw reply related

* Re: [PATCH BlueZ] monitor: Add decoding for Microsoft defined event
From: Archie Pusaka @ 2026-05-13  4:09 UTC (permalink / raw)
  To: linux-bluetooth, Luiz Augusto von Dentz
In-Reply-To: <20260415073940.739683-1-apusaka@google.com>

Hi maintainers,

Could you review this patch? Thanks!

On Wed, 15 Apr 2026 at 15:40, Archie Pusaka <apusaka@google.com> wrote:
>
> From: Archie Pusaka <apusaka@chromium.org>
>
> This adds decoders to MSFT LE monitor device event
> ---
>
>  monitor/msft.c   | 78 +++++++++++++++++++++++++++++++++++++++++++++++-
>  monitor/msft.h   |  1 +
>  monitor/packet.c | 44 ++++++++++++++++++++++-----
>  3 files changed, 115 insertions(+), 8 deletions(-)
>
> diff --git a/monitor/msft.c b/monitor/msft.c
> index 054f34006..d41f10d68 100644
> --- a/monitor/msft.c
> +++ b/monitor/msft.c
> @@ -41,6 +41,8 @@
>
>  #define COLOR_COMMAND          COLOR_BLUE
>  #define COLOR_COMMAND_UNKNOWN  COLOR_WHITE_BG
> +#define COLOR_EVENT            COLOR_MAGENTA
> +#define COLOR_EVENT_UNKNOWN    COLOR_WHITE_BG
>
>  static void null_cmd(const void *data, uint16_t size)
>  {
> @@ -299,10 +301,72 @@ const struct vendor_ocf *msft_vendor_ocf(void)
>         return &vendor_ocf_entry;
>  }
>
> +static void monitor_device_evt(const void *data, uint16_t size)
> +{
> +       const struct msft_evt_monitor_device *evt = data;
> +       const char *str_state;
> +
> +       packet_print_addr(NULL, evt->addr, evt->addr_type);
> +       print_field("Monitor handle: %u", evt->handle);
> +
> +       switch (evt->state) {
> +       case 0x00:
> +               str_state = "Stop monitoring";
> +               break;
> +       case 0x01:
> +               str_state = "Start monitoring";
> +               break;
> +       default:
> +               str_state = "Reserved";
> +               break;
> +       }
> +
> +       print_field("State: %s (0x%2.2x)", str_state, evt->state);
> +}
> +
> +static const struct {
> +       uint8_t code;
> +       const char *str;
> +       func_t evt_func;
> +} evt_table[] = {
> +       { 0x01, "RSSI Event" },
> +       { 0x02, "LE Monitor Device Event", monitor_device_evt },
> +       { }
> +};
> +
>  static void msft_evt(struct timeval *tv, uint16_t index,
>                         const void *data, uint8_t size)
>  {
> -       packet_hexdump(data, size);
> +       uint8_t code = get_u8(data);
> +       const char *code_color, *code_str = NULL;
> +       func_t code_func = NULL;
> +       int i;
> +
> +       for (i = 0; evt_table[i].str; i++) {
> +               if (evt_table[i].code == code) {
> +                       code_str = evt_table[i].str;
> +                       code_func = evt_table[i].evt_func;
> +                       break;
> +               }
> +       }
> +
> +       if (code_str) {
> +               if (code_func)
> +                       code_color = COLOR_EVENT;
> +               else
> +                       code_color = COLOR_EVENT_UNKNOWN;
> +       } else {
> +               code_color = COLOR_EVENT_UNKNOWN;
> +               code_str = "Unknown";
> +       }
> +
> +       print_indent(6, code_color, "", code_str, COLOR_OFF,
> +                                               " (0x%2.2x)", code);
> +
> +       if (code_func)
> +               code_func(data, size);
> +       else
> +               packet_hexdump(data + 1, size - 1);
>  }
>
>  static const struct vendor_evt vendor_evt_entry = {
> @@ -313,3 +377,15 @@ const struct vendor_evt *msft_vendor_evt(void)
>  {
>         return &vendor_evt_entry;
>  }
> +
> +bool msft_event_code_valid(uint8_t code)
> +{
> +       int i;
> +
> +       for (i = 0; evt_table[i].str; i++) {
> +               if (evt_table[i].code == code)
> +                       return true;
> +       }
> +
> +       return false;
> +}
> diff --git a/monitor/msft.h b/monitor/msft.h
> index e6e3019be..ff6c28011 100644
> --- a/monitor/msft.h
> +++ b/monitor/msft.h
> @@ -187,3 +187,4 @@ struct vendor_evt;
>
>  const struct vendor_ocf *msft_vendor_ocf(void);
>  const struct vendor_evt *msft_vendor_evt(void);
> +bool msft_event_code_valid(uint8_t code);
> diff --git a/monitor/packet.c b/monitor/packet.c
> index ff0b1cac2..02f69dfca 100644
> --- a/monitor/packet.c
> +++ b/monitor/packet.c
> @@ -450,8 +450,10 @@ void packet_set_fallback_manufacturer(uint16_t manufacturer)
>
>  void packet_set_msft_evt_prefix(const uint8_t *prefix, uint8_t len)
>  {
> -       if (index_current < MAX_INDEX && len < 8)
> +       if (index_current < MAX_INDEX && len < 8) {
>                 memcpy(index_list[index_current].msft_evt_prefix, prefix, len);
> +               index_list[index_current].msft_evt_len = len;
> +       }
>  }
>
>  static void cred_pid(struct ucred *cred, char *str, size_t len)
> @@ -4359,7 +4361,8 @@ static int addr2str(const uint8_t *addr, char *str)
>                         addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
>  }
>
> -static int get_msft_opcode(uint16_t manufacturer) {
> +static int get_msft_opcode(uint16_t manufacturer)
> +{
>         switch (manufacturer) {
>         case COMPANY_ID_INTEL:
>                 return 0xFC1E;
> @@ -4374,7 +4377,23 @@ static int get_msft_opcode(uint16_t manufacturer) {
>         default:
>                 return BT_HCI_CMD_NOP;
>         }
> +}
> +
> +static bool msft_event_prefix_match(const void *data, int size)
> +{
> +       const void *prefix = index_list[index_current].msft_evt_prefix;
> +       int prefix_len = index_list[index_current].msft_evt_len;
> +
> +       /*
> +        * MSFT event has one byte of event code following the MSFT prefix.
> +        * We need to check the event code is valid, as it's possible for
> +        * a vendor to use the same MSFT prefix but for other events.
> +        */
> +       if (size >= prefix_len + 1 && !memcmp(prefix, data, prefix_len))
> +               return msft_event_code_valid(
> +                               ((const uint8_t *) data)[prefix_len]);
>
> +       return false;
>  }
>
>  void packet_monitor(struct timeval *tv, struct ucred *cred,
> @@ -10925,11 +10944,16 @@ static const struct vendor_ocf *current_vendor_ocf(uint16_t ocf)
>  }
>
>  static const struct vendor_evt *current_vendor_evt(const void *data,
> -                                                       int *consumed_size)
> +                                       uint8_t size, int *consumed_size)
>  {
>         uint16_t manufacturer;
>         uint8_t evt = *((const uint8_t *) data);
>
> +       if (msft_event_prefix_match(data, size)) {
> +               *consumed_size = index_list[index_current].msft_evt_len;
> +               return msft_vendor_evt();
> +       }
> +
>         /* A regular vendor event consumes 1 byte. */
>         *consumed_size = 1;
>
> @@ -10948,10 +10972,13 @@ static const struct vendor_evt *current_vendor_evt(const void *data,
>         return NULL;
>  }
>
> -static const char *current_vendor_evt_str(void)
> +static const char *current_vendor_evt_str(const void *data, uint8_t size)
>  {
>         uint16_t manufacturer;
>
> +       if (msft_event_prefix_match(data, size))
> +               return "Microsoft";
> +
>         if (index_current < MAX_INDEX)
>                 manufacturer = index_list[index_current].manufacturer;
>         else
> @@ -13547,17 +13574,20 @@ static void vendor_evt(struct timeval *tv, uint16_t index,
>         struct subevent_data vendor_data;
>         char vendor_str[150];
>         int consumed_size;
> -       const struct vendor_evt *vnd = current_vendor_evt(data, &consumed_size);
> +       const struct vendor_evt *vnd = current_vendor_evt(data, size,
> +                                                               &consumed_size);
>
>         if (vnd) {
> -               const char *str = current_vendor_evt_str();
> +               const char *str = current_vendor_evt_str(data, size);
>
>                 if (str) {
>                         snprintf(vendor_str, sizeof(vendor_str),
>                                                 "%s %s", str, vnd->str);
>                         vendor_data.str = vendor_str;
> -               } else
> +               } else {
>                         vendor_data.str = vnd->str;
> +               }
> +
>                 vendor_data.subevent = vnd->evt;
>                 vendor_data.func = vnd->evt_func;
>                 vendor_data.size = vnd->evt_size;
> --
> 2.54.0.rc0.605.g598a273b03-goog
>

^ permalink raw reply

* RE: [v4] Bluetooth: Add Synaptics 4384 Chip Support
From: bluez.test.bot @ 2026-05-13  4:40 UTC (permalink / raw)
  To: linux-bluetooth, kaihsin.chung
In-Reply-To: <20260513022008.3238060-1-kaihsin.chung@synaptics.com>

[-- Attachment #1: Type: text/plain, Size: 1846 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=1093859

---Test result---

Test Summary:
CheckPatch                    FAIL      1.05 seconds
GitLint                       PASS      0.33 seconds
SubjectPrefix                 PASS      0.35 seconds
BuildKernel                   PASS      25.97 seconds
CheckAllWarning               PASS      29.42 seconds
CheckSparse                   PASS      27.85 seconds
BuildKernel32                 PASS      25.96 seconds
TestRunnerSetup               PASS      537.07 seconds
IncrementalBuild              PASS      25.45 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[v4] Bluetooth: Add Synaptics 4384 Chip Support
WARNING: DT compatible string "brcm,bcm4384-bt" appears un-documented -- check ./Documentation/devicetree/bindings/
#160: FILE: drivers/bluetooth/hci_bcm.c:1612:
+	{ .compatible = "brcm,bcm4384-bt" },

WARNING: From:/Signed-off-by: email name mismatch: 'From: Kaihsin Chung <kaihsin.chung@synaptics.com>' != 'Signed-off-by: kaihsin Chung <kaihsin.chung@synaptics.com>'

total: 0 errors, 2 warnings, 31 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/patch/14570021.patch has style problems, please review.

NOTE: Ignored message types: UNKNOWN_COMMIT_ID

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.




https://github.com/bluez/bluetooth-next/pull/180

---
Regards,
Linux Bluetooth


^ permalink raw reply

* RE: Bluetooth: bnep: reject short frames before parsing
From: bluez.test.bot @ 2026-05-13  4:41 UTC (permalink / raw)
  To: linux-bluetooth, rollkingzzc
In-Reply-To: <20260513031246.651762-1-rollkingzzc@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 936 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=1093891

---Test result---

Test Summary:
CheckPatch                    PASS      0.71 seconds
GitLint                       PASS      0.29 seconds
SubjectPrefix                 PASS      0.11 seconds
BuildKernel                   PASS      26.69 seconds
CheckAllWarning               PASS      29.05 seconds
CheckSparse                   PASS      27.92 seconds
BuildKernel32                 PASS      25.69 seconds
TestRunnerSetup               PASS      568.44 seconds
TestRunner_bnep-tester        PASS      18.92 seconds
IncrementalBuild              PASS      25.28 seconds



https://github.com/bluez/bluetooth-next/pull/181

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [PATCH] Bluetooth: hci_uart: fix UAF in hci_uart_tty_close()
From: w15303746062 @ 2026-05-13  6:45 UTC (permalink / raw)
  To: marcel, luiz.dentz
  Cc: linux-bluetooth, linux-serial, linux-kernel, Mingyu Wang

From: Mingyu Wang <25181214217@stu.xidian.edu.cn>

A Use-After-Free (UAF) vulnerability and a subsequent General Protection
Fault (GPF) were observed in h5_recv() due to a race condition between
the initialization of the HCI UART line discipline and concurrent TTY
hangup via TIOCVHANGUP.

The issue arises because the workqueues (init_ready and write_work) are
only cancelled if the HCI_UART_PROTO_READY flag is set. However, during
the protocol initialization phase (HCI_UART_PROTO_INIT), the underlying
protocol (e.g., H5) may schedule work (such as sending sync/config
packets). If a hangup occurs before the setup completes and the READY
flag is set, hci_uart_tty_close() skips the cancel_work_sync() calls
and proceeds to free the `hu` struct.

When the delayed workqueue finally executes, it blindly dereferences
the freed `hu` struct, causing ODEBUG warnings and kernel panics.

Fix this by moving the cancel_work_sync() calls outside the
HCI_UART_PROTO_READY check, ensuring that any pending works are
unconditionally cancelled before the hci_uart structure is freed.

Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
---
 drivers/bluetooth/hci_ldisc.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 275ea865bc29..566e1c525ee2 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -544,14 +544,18 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 	if (hdev)
 		hci_uart_close(hdev);
 
+	/*
+	 * Always cancel workqueues unconditionally before freeing the hu
+	 * struct, as they might be active during the PROTO_INIT phase.
+	 */
+	cancel_work_sync(&hu->init_ready);
+	cancel_work_sync(&hu->write_work);
+
 	if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
 		percpu_down_write(&hu->proto_lock);
 		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
 		percpu_up_write(&hu->proto_lock);
 
-		cancel_work_sync(&hu->init_ready);
-		cancel_work_sync(&hu->write_work);
-
 		if (hdev) {
 			if (test_bit(HCI_UART_REGISTERED, &hu->flags))
 				hci_unregister_dev(hdev);
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v2] Bluetooth: btusb: Allow firmware re-download when version matches
From: Shuai Zhang @ 2026-05-13  7:50 UTC (permalink / raw)
  To: Luiz Augusto von Dentz
  Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, linux-arm-msm,
	cheng.jiang, quic_chezhou, wei.deng, jinwang.li, mengshi.wu
In-Reply-To: <CABBYNZLP+rBrjhdKJLE7N47Bg-g4-6E3vS3yZXvMKwYQ2rMcUA@mail.gmail.com>

Hi Luiz

On 4/29/2026 11:17 PM, Luiz Augusto von Dentz wrote:
> Hi Shuai,
>
> On Wed, Apr 29, 2026 at 8:12 AM Shuai Zhang
> <shuai.zhang@oss.qualcomm.com> wrote:
>> The Bluetooth host decides whether to download firmware by reading the
>> controller firmware download completion flag and firmware version
>> information.
>>
>> If a USB error occurs during the firmware download process (for example
>> due to a USB disconnect), the download is aborted immediately. An
>> incomplete firmware transfer does not cause the controller to set the
>> download completion flag, but the firmware version information may be
>> updated at an early stage of the download process.
> Hold on, if the download has been aborted then the version should be
> reverted, or rather just update once the firmware loading is complete,
> so this indicates there is a bug somewhere that needs fixing, not
> worked around.
>
>> In this case, after USB reconnection, the host attempts to re-download
>> the firmware because the download completion flag is not set. However,
>> since the controller reports the same firmware version as the target
>> firmware, the download is skipped. This ultimately results in the
>> firmware not being properly updated on the controller.
>>
>> This change removes the restriction that skips firmware download when
>> the versions are equal. It covers scenarios where the USB connection
>> can be disconnected at any time and ensures that firmware download can
>> be retriggered after USB reconnection, allowing the Bluetooth firmware
>> to be correctly and completely updated.
>>
>> Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
>> ---
>> Changes v2:
>> - Update code comments and commit message to reflect the correct logic.
>> - Align the commit title with upstream conventions.
>> - Link v1
>>    https://lore.kernel.org/all/20260108074353.1027877-1-shuai.zhang@oss.qualcomm.com/
>> ---
>>   drivers/bluetooth/btusb.c | 8 +++++++-
>>   1 file changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
>> index 572091e60..70abbabea 100644
>> --- a/drivers/bluetooth/btusb.c
>> +++ b/drivers/bluetooth/btusb.c
>> @@ -3550,7 +3550,13 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
>>                      "firmware rome 0x%x build 0x%x",
>>                      rver_rom, rver_patch, ver_rom, ver_patch);
>>
>> -       if (rver_rom != ver_rom || rver_patch <= ver_patch) {
>> +       /* Allow rampatch when the patch version equals the firmware version.
>> +        * A firmware download may be aborted by a transient USB error (e.g.
>> +        * disconnect) after the controller updates version info but before
>> +        * completion.
>> +        * Allowing equal versions enables re-flashing during recovery.
>> +        */
>> +       if (rver_rom != ver_rom || rver_patch < ver_patch) {
> As I said above, this sounds more like a workaround. That said, I
> wonder why it would print an error if the version matches, it sounds
> to be that if the version matches it should just skip and consider it
> has been loaded already in case the actual problem is fixed by setting
> the new version only when loading has been completed.


Correct, we cannot reliably detect if the download was aborted mid-flight,
so the version information may not always be accurate.

However, we only force a reload in cases where the firmware integrity
cannot be guaranteed. If the firmware download has completed successfully,
even if a USB disconnect happens afterward, we will not reload it, as the
controller already contains a complete and valid firmware.


>>                  bt_dev_err(hdev, "rampatch file version did not match with firmware");
>>                  err = -EINVAL;
>>                  goto done;
>> --
>> 2.34.1
>>
>

^ permalink raw reply

* Re: [PATCH v2] Bluetooth: btusb: Allow firmware re-download when version matches
From: Shuai Zhang @ 2026-05-13  7:52 UTC (permalink / raw)
  To: Luiz Augusto von Dentz
  Cc: Marcel Holtmann, linux-bluetooth, linux-kernel, linux-arm-msm,
	cheng.jiang, quic_chezhou, wei.deng, jinwang.li, mengshi.wu
In-Reply-To: <CABBYNZKbVT2xXqedwoenuU0YroJO-3gyhJGSixt0zvodLez0qQ@mail.gmail.com>

Hi  Luiz

On 4/30/2026 12:14 AM, Luiz Augusto von Dentz wrote:
> Hi Shuai,
>
> On Wed, Apr 29, 2026 at 11:17 AM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
>> Hi Shuai,
>>
>> On Wed, Apr 29, 2026 at 8:12 AM Shuai Zhang
>> <shuai.zhang@oss.qualcomm.com> wrote:
>>> The Bluetooth host decides whether to download firmware by reading the
>>> controller firmware download completion flag and firmware version
>>> information.
>>>
>>> If a USB error occurs during the firmware download process (for example
>>> due to a USB disconnect), the download is aborted immediately. An
>>> incomplete firmware transfer does not cause the controller to set the
>>> download completion flag, but the firmware version information may be
>>> updated at an early stage of the download process.
>> Hold on, if the download has been aborted then the version should be
>> reverted, or rather just update once the firmware loading is complete,
>> so this indicates there is a bug somewhere that needs fixing, not
>> worked around.
>>
>>> In this case, after USB reconnection, the host attempts to re-download
>>> the firmware because the download completion flag is not set. However,
>>> since the controller reports the same firmware version as the target
>>> firmware, the download is skipped. This ultimately results in the
>>> firmware not being properly updated on the controller.
>>>
>>> This change removes the restriction that skips firmware download when
>>> the versions are equal. It covers scenarios where the USB connection
>>> can be disconnected at any time and ensures that firmware download can
>>> be retriggered after USB reconnection, allowing the Bluetooth firmware
>>> to be correctly and completely updated.
>>>
>>> Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
>>> ---
>>> Changes v2:
>>> - Update code comments and commit message to reflect the correct logic.
>>> - Align the commit title with upstream conventions.
>>> - Link v1
>>>    https://lore.kernel.org/all/20260108074353.1027877-1-shuai.zhang@oss.qualcomm.com/
>>> ---
>>>   drivers/bluetooth/btusb.c | 8 +++++++-
>>>   1 file changed, 7 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
>>> index 572091e60..70abbabea 100644
>>> --- a/drivers/bluetooth/btusb.c
>>> +++ b/drivers/bluetooth/btusb.c
>>> @@ -3550,7 +3550,13 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
>>>                      "firmware rome 0x%x build 0x%x",
>>>                      rver_rom, rver_patch, ver_rom, ver_patch);
>>>
>>> -       if (rver_rom != ver_rom || rver_patch <= ver_patch) {
>>> +       /* Allow rampatch when the patch version equals the firmware version.
>>> +        * A firmware download may be aborted by a transient USB error (e.g.
>>> +        * disconnect) after the controller updates version info but before
>>> +        * completion.
>>> +        * Allowing equal versions enables re-flashing during recovery.
>>> +        */
>>> +       if (rver_rom != ver_rom || rver_patch < ver_patch) {
>> As I said above, this sounds more like a workaround. That said, I
>> wonder why it would print an error if the version matches, it sounds
>> to be that if the version matches it should just skip and consider it
>> has been loaded already in case the actual problem is fixed by setting
>> the new version only when loading has been completed.
> Btw, the following also seem valid although not introduced by this change:
>
> https://sashiko.dev/#/patchset/20260429121207.1306526-1-shuai.zhang%40oss.qualcomm.com


I will check this and submit a new patch if it is issue.


>
>>>                  bt_dev_err(hdev, "rampatch file version did not match with firmware");
>>>                  err = -EINVAL;
>>>                  goto done;
>>> --
>>> 2.34.1
>>>
>>
>> --
>> Luiz Augusto von Dentz

Thanks,

Shuai

>
>

^ permalink raw reply

* RE: Bluetooth: hci_uart: fix UAF in hci_uart_tty_close()
From: bluez.test.bot @ 2026-05-13  7:54 UTC (permalink / raw)
  To: linux-bluetooth, w15303746062
In-Reply-To: <20260513064547.352601-1-w15303746062@163.com>

[-- Attachment #1: Type: text/plain, Size: 882 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=1093952

---Test result---

Test Summary:
CheckPatch                    PASS      1.64 seconds
GitLint                       PASS      0.35 seconds
SubjectPrefix                 PASS      0.13 seconds
BuildKernel                   PASS      24.81 seconds
CheckAllWarning               PASS      27.31 seconds
CheckSparse                   PASS      26.18 seconds
BuildKernel32                 PASS      28.14 seconds
TestRunnerSetup               PASS      519.12 seconds
IncrementalBuild              PASS      24.50 seconds



https://github.com/bluez/bluetooth-next/pull/182

---
Regards,
Linux Bluetooth


^ permalink raw reply

* [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in l2cap_disconn_ind (3)
From: syzbot @ 2026-05-13  8:12 UTC (permalink / raw)
  To: linux-bluetooth, linux-kernel, luiz.dentz, marcel, syzkaller-bugs

Hello,

syzbot found the following issue on:

HEAD commit:    1bfaee9d3351 Merge tag 'fsverity-for-linus' of git://git.k..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=132d7e96580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=59da38148f3a3d24
dashboard link: https://syzkaller.appspot.com/bug?extid=9c40ad7c6ed7165e46e8
compiler:       gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/b5cda08ac5a6/disk-1bfaee9d.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/aad7c1ec90c4/vmlinux-1bfaee9d.xz
kernel image: https://storage.googleapis.com/syzbot-assets/a51d7d927815/bzImage-1bfaee9d.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+9c40ad7c6ed7165e46e8@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: slab-use-after-free in l2cap_disconn_ind+0xd7/0xf0 net/bluetooth/l2cap_core.c:7430
Read of size 1 at addr ffff88807ee53278 by task kworker/u9:1/4933

CPU: 1 UID: 0 PID: 4933 Comm: kworker/u9:1 Tainted: G             L      syzkaller #0 PREEMPT(full) 
Tainted: [L]=SOFTLOCKUP
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
Workqueue: hci2 hci_conn_timeout
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:94 [inline]
 dump_stack_lvl+0x100/0x190 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:378 [inline]
 print_report+0x13d/0x4b0 mm/kasan/report.c:482
 kasan_report+0xdf/0x1d0 mm/kasan/report.c:595
 l2cap_disconn_ind+0xd7/0xf0 net/bluetooth/l2cap_core.c:7430
 hci_proto_disconn_ind include/net/bluetooth/hci_core.h:2115 [inline]
 hci_conn_timeout+0x1dc/0x230 net/bluetooth/hci_conn.c:646
 process_one_work+0xa0e/0x1980 kernel/workqueue.c:3302
 process_scheduled_works kernel/workqueue.c:3385 [inline]
 worker_thread+0x5ef/0xe50 kernel/workqueue.c:3466
 kthread+0x370/0x450 kernel/kthread.c:436
 ret_from_fork+0x72b/0xd50 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>

Allocated by task 16760:
 kasan_save_stack+0x30/0x50 mm/kasan/common.c:57
 kasan_save_track+0x14/0x30 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:415
 kmalloc_noprof include/linux/slab.h:950 [inline]
 kzalloc_noprof include/linux/slab.h:1188 [inline]
 l2cap_conn_add.part.0+0x60/0xb00 net/bluetooth/l2cap_core.c:7001
 l2cap_conn_add include/net/bluetooth/l2cap.h:840 [inline]
 l2cap_chan_connect+0x1435/0x1f90 net/bluetooth/l2cap_core.c:7192
 l2cap_sock_connect+0x37a/0x770 net/bluetooth/l2cap_sock.c:256
 __sys_connect_file+0x141/0x1a0 net/socket.c:2148
 __sys_connect+0x141/0x170 net/socket.c:2167
 __do_sys_connect net/socket.c:2173 [inline]
 __se_sys_connect net/socket.c:2170 [inline]
 __x64_sys_connect+0x72/0xb0 net/socket.c:2170
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x10b/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 16756:
 kasan_save_stack+0x30/0x50 mm/kasan/common.c:57
 kasan_save_track+0x14/0x30 mm/kasan/common.c:78
 kasan_save_free_info+0x3b/0x70 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5f/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2689 [inline]
 slab_free mm/slub.c:6250 [inline]
 kfree+0x223/0x6c0 mm/slub.c:6565
 l2cap_conn_free net/bluetooth/l2cap_core.c:1823 [inline]
 kref_put include/linux/kref.h:65 [inline]
 l2cap_conn_put net/bluetooth/l2cap_core.c:1835 [inline]
 l2cap_conn_del+0x57f/0x710 net/bluetooth/l2cap_core.c:1815
 l2cap_connect_cfm+0x9bb/0xf80 net/bluetooth/l2cap_core.c:7374
 hci_connect_cfm include/net/bluetooth/hci_core.h:2139 [inline]
 hci_conn_failed+0x188/0x360 net/bluetooth/hci_conn.c:1409
 hci_abort_conn_sync+0x7d9/0xb20 net/bluetooth/hci_sync.c:5763
 hci_disconnect_all_sync.constprop.0.isra.0+0x155/0x430 net/bluetooth/hci_sync.c:5786
 hci_suspend_sync+0x8b7/0xa70 net/bluetooth/hci_sync.c:6262
 hci_suspend_dev+0x31d/0x540 net/bluetooth/hci_core.c:2850
 hci_suspend_notifier+0x21e/0x330 net/bluetooth/hci_core.c:2421
 notifier_call_chain+0x99/0x400 kernel/notifier.c:85
 notifier_call_chain_robust kernel/notifier.c:120 [inline]
 blocking_notifier_call_chain_robust kernel/notifier.c:345 [inline]
 blocking_notifier_call_chain_robust+0xc8/0x160 kernel/notifier.c:333
 pm_notifier_call_chain_robust+0x27/0x60 kernel/power/main.c:172
 snapshot_open+0x189/0x2a0 kernel/power/user.c:77
 misc_open+0x26d/0x450 drivers/char/misc.c:163
 chrdev_open+0x234/0x6a0 fs/char_dev.c:411
 do_dentry_open+0x6d8/0x1660 fs/open.c:947
 vfs_open+0x82/0x3f0 fs/open.c:1079
 do_open fs/namei.c:4699 [inline]
 path_openat+0x208c/0x31a0 fs/namei.c:4858
 do_file_open+0x20e/0x430 fs/namei.c:4887
 do_sys_openat2+0x10d/0x1e0 fs/open.c:1364
 do_sys_open fs/open.c:1370 [inline]
 __do_sys_openat fs/open.c:1386 [inline]
 __se_sys_openat fs/open.c:1381 [inline]
 __x64_sys_openat+0x12d/0x210 fs/open.c:1381
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x10b/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff88807ee53000
 which belongs to the cache kmalloc-1k of size 1024
The buggy address is located 632 bytes inside of
 freed 1024-byte region [ffff88807ee53000, ffff88807ee53400)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x7ee50
head: order:3 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
flags: 0xfff00000000040(head|node=0|zone=1|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 00fff00000000040 ffff88813fe34dc0 dead000000000100 dead000000000122
raw: 0000000000000000 0000000800100010 00000000f5000000 0000000000000000
head: 00fff00000000040 ffff88813fe34dc0 dead000000000100 dead000000000122
head: 0000000000000000 0000000800100010 00000000f5000000 0000000000000000
head: 00fff00000000003 fffffffffffffe01 00000000ffffffff 00000000ffffffff
head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000008
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 3, migratetype Unmovable, gfp_mask 0xd2820(GFP_ATOMIC|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 1151, tgid 1151 (kworker/u8:8), ts 131280693452, free_ts 131177469088
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x153/0x170 mm/page_alloc.c:1858
 prep_new_page mm/page_alloc.c:1866 [inline]
 get_page_from_freelist+0x11a6/0x33b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x27c/0x2bc0 mm/page_alloc.c:5226
 alloc_slab_page mm/slub.c:3278 [inline]
 allocate_slab mm/slub.c:3467 [inline]
 new_slab+0xa6/0x6c0 mm/slub.c:3525
 refill_objects+0x277/0x420 mm/slub.c:7255
 refill_sheaf mm/slub.c:2816 [inline]
 __pcs_replace_empty_main+0x375/0x650 mm/slub.c:4651
 alloc_from_pcs mm/slub.c:4749 [inline]
 slab_alloc_node mm/slub.c:4883 [inline]
 __do_kmalloc_node mm/slub.c:5294 [inline]
 __kmalloc_noprof+0x688/0x850 mm/slub.c:5307
 kmalloc_noprof include/linux/slab.h:954 [inline]
 kzalloc_noprof include/linux/slab.h:1188 [inline]
 neigh_alloc net/core/neighbour.c:521 [inline]
 ___neigh_create+0x1545/0x2950 net/core/neighbour.c:655
 ip6_finish_output2+0xffa/0x1ce0 net/ipv6/ip6_output.c:128
 __ip6_finish_output+0x357/0xdf0 net/ipv6/ip6_output.c:208
 ip6_finish_output net/ipv6/ip6_output.c:219 [inline]
 NF_HOOK_COND include/linux/netfilter.h:307 [inline]
 ip6_output+0x2aa/0xa60 net/ipv6/ip6_output.c:246
 dst_output include/net/dst.h:470 [inline]
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ndisc_send_skb+0xa85/0x1bf0 net/ipv6/ndisc.c:512
 ndisc_send_rs+0x129/0x680 net/ipv6/ndisc.c:723
 addrconf_rs_timer+0x424/0x880 net/ipv6/addrconf.c:4049
 call_timer_fn+0x19a/0x640 kernel/time/timer.c:1748
 expire_timers kernel/time/timer.c:1799 [inline]
 __run_timers+0x75f/0xaf0 kernel/time/timer.c:2374
page last free pid 5637 tgid 5637 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1402 [inline]
 __free_frozen_pages+0x747/0x1040 mm/page_alloc.c:2943
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x47/0xf0 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x1a0/0x1f0 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x69/0x90 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4569 [inline]
 slab_alloc_node mm/slub.c:4898 [inline]
 kmem_cache_alloc_noprof+0x241/0x6e0 mm/slub.c:4905
 alloc_filename fs/namei.c:142 [inline]
 do_getname+0x35/0x390 fs/namei.c:182
 getname include/linux/fs.h:2526 [inline]
 class_filename_constructor include/linux/fs.h:2553 [inline]
 do_sys_openat2+0xc5/0x1e0 fs/open.c:1363
 do_sys_open fs/open.c:1370 [inline]
 __do_sys_openat fs/open.c:1386 [inline]
 __se_sys_openat fs/open.c:1381 [inline]
 __x64_sys_openat+0x12d/0x210 fs/open.c:1381
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x10b/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Memory state around the buggy address:
 ffff88807ee53100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff88807ee53180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88807ee53200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
                                                                ^
 ffff88807ee53280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
 ffff88807ee53300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply

* Re: [PATCH] Bluetooth: hci_uart: fix UAF in hci_uart_tty_close()
From: Paul Menzel @ 2026-05-13  9:04 UTC (permalink / raw)
  To: Mingyu Wang, Mingyu Wang
  Cc: marcel, luiz.dentz, linux-bluetooth, linux-serial, linux-kernel
In-Reply-To: <20260513064547.352601-1-w15303746062@163.com>

Dear Mingyu,


Thank you for the patch, and your work on the Linux kernel.

Am 13.05.26 um 08:45 schrieb w15303746062@163.com:
> From: Mingyu Wang <25181214217@stu.xidian.edu.cn>
> 
> A Use-After-Free (UAF) vulnerability and a subsequent General Protection
> Fault (GPF) were observed in h5_recv() due to a race condition between
> the initialization of the HCI UART line discipline and concurrent TTY
> hangup via TIOCVHANGUP.

Please elaborate, in what setup it was observed, and please add an 
excerpt of the trace.

> The issue arises because the workqueues (init_ready and write_work) are
> only cancelled if the HCI_UART_PROTO_READY flag is set. However, during
> the protocol initialization phase (HCI_UART_PROTO_INIT), the underlying
> protocol (e.g., H5) may schedule work (such as sending sync/config
> packets). If a hangup occurs before the setup completes and the READY
> flag is set, hci_uart_tty_close() skips the cancel_work_sync() calls
> and proceeds to free the `hu` struct.
> 
> When the delayed workqueue finally executes, it blindly dereferences
> the freed `hu` struct, causing ODEBUG warnings and kernel panics.
> 
> Fix this by moving the cancel_work_sync() calls outside the
> HCI_UART_PROTO_READY check, ensuring that any pending works are
> unconditionally cancelled before the hci_uart structure is freed.

Please add a Fixes: tag, so it gets backported.

Also, please add a Link: tag with a URL to the test case, or include it 
in the commit message.

> Signed-off-by: Mingyu Wang <25181214217@stu.xidian.edu.cn>
> ---
>   drivers/bluetooth/hci_ldisc.c | 10 +++++++---
>   1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 275ea865bc29..566e1c525ee2 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -544,14 +544,18 @@ static void hci_uart_tty_close(struct tty_struct *tty)
>   	if (hdev)
>   		hci_uart_close(hdev);
>   
> +	/*
> +	 * Always cancel workqueues unconditionally before freeing the hu
> +	 * struct, as they might be active during the PROTO_INIT phase.
> +	 */
> +	cancel_work_sync(&hu->init_ready);
> +	cancel_work_sync(&hu->write_work);
> +
>   	if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
>   		percpu_down_write(&hu->proto_lock);
>   		clear_bit(HCI_UART_PROTO_READY, &hu->flags);
>   		percpu_up_write(&hu->proto_lock);
>   
> -		cancel_work_sync(&hu->init_ready);
> -		cancel_work_sync(&hu->write_work);
> -
>   		if (hdev) {
>   			if (test_bit(HCI_UART_REGISTERED, &hu->flags))
>   				hci_unregister_dev(hdev);


Kind regards,

Paul


PS: If you resend, and don’t know yet (you have commits in the Linux 
kernel already), please add v2 to the tag. (`git format-patch -2 …` or 
an equivalent option to your tooling.

PPS: sashiko.dev did not pick this patch up yet [1].


[1]: https://sashiko.dev/#/?list=org.kernel.vger.linux-bluetooth

^ permalink raw reply

* [PATCH v5] Bluetooth: btrtl: Add firmware format v3 support
From: Hilda Wu @ 2026-05-13  9:24 UTC (permalink / raw)
  To: marcel
  Cc: luiz.dentz, linux-bluetooth, linux-kernel, alex_lu, jason_mao,
	zoey_zhou, max.chou

Realtek updated its Bluetooth firmware format to v3.
This patch extends the btrtl driver to recognise and parse the new v3 file
format, including:
- New signature string and image ID definitions
- Extension of btrtl_device_info to store v3-specific metadata
- Logic to extract and load firmware data out of v3 images
- Maintains compatibility with existing v2 firmware format

This is required for future Realtek Bluetooth chips that ship with
v3 firmware.
The RTL8922D is the first IC to use firmware format V3, so the following
example uses the RTL8922D's log as expected fw format v3 output:

Bluetooth: btrtl_read_chip_id() hci0: RTL: chip_id status=0x00 id=0x37
Bluetooth: btrtl_initialize() hci0: RTL: examining hci_ver=0d
hci_rev=000d lmp_ver=0d lmp_subver=8922
Bluetooth: rtl_read_rom_version() hci0: RTL: rom_version status=0 version=1
Bluetooth: btrtl_initialize() hci0: RTL: btrtl_initialize: key id 0
Bluetooth: rtl_load_file() hci0: RTL: loading rtl_bt/rtl8922du_fw.bin
Bluetooth: rtl_load_file() hci0: RTL: loading rtl_bt/rtl8922du_config.bin
Bluetooth: rtlbt_parse_firmware_v3() hci0: RTL: key id 0
Bluetooth: rtlbt_parse_section_v3() hci0: RTL: image (f000:00), chip id
55, cut 0x02, len 00007185
Bluetooth: rtlbt_parse_section_v3() hci0: RTL: image version: 35fd7908
Bluetooth: rtlbt_parse_config() hci0: RTL: config file:
rtl_bt/rtl8922du_config_f000.bin
Bluetooth: rtlbt_parse_section_v3() hci0: RTL: image (f002:00), chip id
55, cut 0x02, len 000078f5
Bluetooth: rtlbt_parse_section_v3() hci0: RTL: image version: 47b6874d
Bluetooth: rtlbt_parse_config() hci0: RTL: config file:
rtl_bt/rtl8922du_config_f002.bin
Bluetooth: rtlbt_parse_firmware_v3() hci0: RTL: image payload total len:
0x0000ea7a
Bluetooth: rtl_finalize_download() hci0: RTL: Watchdog reset status 00
Bluetooth: rtl_finalize_download() hci0: RTL: fw version 0x47b6874d

Signed-off-by: Alex Lu <alex_lu@realsil.com.cn>
Signed-off-by: Zoey Zhou <zoey_zhou@realsil.com.cn>
Signed-off-by: Hilda Wu <hildawu@realtek.com>

---
Change in V5:
- Independent support for 8922D section
- Define relevant macros to increase readability
- Added format v3 description and differences
- Adjusted according to the recommendations
- Adjust to use kzalloc_obj

Change in V4:
- Modify access to skb->data and add descriptions
- Fix hidden issues

Change in V3:
- Fixed cocci warning

Change in V2:
- Fill in the missing symbols
- Fix build warnings
---
 drivers/bluetooth/btrtl.c | 698 +++++++++++++++++++++++++++++++++++++-
 drivers/bluetooth/btrtl.h | 102 ++++++
 drivers/bluetooth/btusb.c |   3 +
 3 files changed, 786 insertions(+), 17 deletions(-)

diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 49ecb18fea45..450b32bcfa63 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -22,6 +22,12 @@
 #define RTL_CHIP_8723CS_XX	5
 #define RTL_EPATCH_SIGNATURE	"Realtech"
 #define RTL_EPATCH_SIGNATURE_V2	"RTBTCore"
+#define RTL_EPATCH_SIGNATURE_V3	"BTNIC003"
+#define RTL_PATCH_V3_1		0x01
+#define RTL_PATCH_V3_2		0x02
+#define IMAGE_ID_F000		0xf000
+#define IMAGE_ID_F001		0xf001
+#define IMAGE_ID_F002		0xf002
 #define RTL_ROM_LMP_8703B	0x8703
 #define RTL_ROM_LMP_8723A	0x1200
 #define RTL_ROM_LMP_8723B	0x8723
@@ -33,7 +39,14 @@
 #define RTL_ROM_LMP_8922A	0x8922
 #define RTL_CONFIG_MAGIC	0x8723ab55
 
-#define RTL_VSC_OP_COREDUMP	0xfcff
+#define RTL_VSC_OP_DOWNLOAD_CMD		0xfc20
+#define RTL_VSC_OP_READ_VENDER		0xfc61
+#define RTL_VSC_OP_WRITE_VENDOR		0xfc62
+#define RTL_VSC_OP_READ_ROM_VER		0xfc6d
+#define RTL_VSC_OP_READ_CHIP_ID		0xfc6f
+#define RTL_VSC_OP_COREDUMP		0xfcff
+#define RTL_VSC_OP_CHECK_DOWNLOAD_STATE	0xfdcf
+#define RTL_VSC_OP_WDG_RESET_CMD	0xfc8e
 
 #define IC_MATCH_FL_LMPSUBV	(1 << 0)
 #define IC_MATCH_FL_HCIREV	(1 << 1)
@@ -50,12 +63,16 @@
 
 #define	RTL_CHIP_SUBVER (&(struct rtl_vendor_cmd) {{0x10, 0x38, 0x04, 0x28, 0x80}})
 #define	RTL_CHIP_REV    (&(struct rtl_vendor_cmd) {{0x10, 0x3A, 0x04, 0x28, 0x80}})
-#define	RTL_SEC_PROJ    (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0xAD, 0x00, 0xb0}})
+#define	RTL_SEC_PROJ_V2 (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0xAD, 0x00, 0xb0}})
+#define	RTL_SEC_PROJ_V3 (&(struct rtl_vendor_cmd) {{0x10, 0xA4, 0x0D, 0x01, 0xa0}})
 
 #define RTL_PATCH_SNIPPETS		0x01
 #define RTL_PATCH_DUMMY_HEADER		0x02
 #define RTL_PATCH_SECURITY_HEADER	0x03
 
+#define CHIP_ID_V3_BASE		55
+#define RTL_VENDOR_WRITE_TYPE		0x21
+
 enum btrtl_chip_id {
 	CHIP_ID_8723A,
 	CHIP_ID_8723B,
@@ -99,8 +116,11 @@ struct btrtl_device_info {
 	int cfg_len;
 	bool drop_fw;
 	int project_id;
+	u32 opcode;
+	u8 fw_type;
 	u8 key_id;
 	struct list_head patch_subsecs;
+	struct list_head patch_images;
 };
 
 static const struct id_table ic_id_table[] = {
@@ -371,6 +391,33 @@ static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
 	return &ic_id_table[i];
 }
 
+static int btrtl_read_chip_id(struct hci_dev *hdev, u8 *chip_id)
+{
+	struct rtl_rp_read_chip_id *rp;
+	struct sk_buff *skb;
+	int ret = 0;
+
+	skb = __hci_cmd_sync(hdev, RTL_VSC_OP_READ_CHIP_ID, 0, NULL, HCI_INIT_TIMEOUT);
+	if (IS_ERR(skb))
+		return PTR_ERR(skb);
+
+	rp = skb_pull_data(skb, sizeof(*rp));
+	if (!rp) {
+		ret = -EIO;
+		goto out;
+	}
+
+	rtl_dev_info(hdev, "chip_id status=0x%02x id=0x%02x",
+		     rp->status, rp->chip_id);
+
+	if (chip_id)
+		*chip_id = rp->chip_id;
+
+out:
+	kfree_skb(skb);
+	return ret;
+}
+
 static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev)
 {
 	struct sk_buff *skb;
@@ -397,8 +444,7 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
 	struct rtl_rom_version_evt *rom_version;
 	struct sk_buff *skb;
 
-	/* Read RTL ROM version command */
-	skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
+	skb = __hci_cmd_sync(hdev, RTL_VSC_OP_READ_ROM_VER, 0, NULL, HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		rtl_dev_err(hdev, "Read ROM version failed (%ld)",
 			    PTR_ERR(skb));
@@ -427,7 +473,7 @@ static int btrtl_vendor_read_reg16(struct hci_dev *hdev,
 	struct sk_buff *skb;
 	int err = 0;
 
-	skb = __hci_cmd_sync(hdev, 0xfc61, sizeof(*cmd), cmd,
+	skb = __hci_cmd_sync(hdev, RTL_VSC_OP_READ_VENDER, sizeof(*cmd), cmd,
 			     HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		err = PTR_ERR(skb);
@@ -449,6 +495,26 @@ static int btrtl_vendor_read_reg16(struct hci_dev *hdev,
 	return 0;
 }
 
+static int btrtl_vendor_write_mem(struct hci_dev *hdev, u32 addr, u32 val)
+{
+	struct rtl_vendor_write_cmd cp;
+	struct sk_buff *skb;
+	int err = 0;
+
+	cp.type = RTL_VENDOR_WRITE_TYPE;
+	cp.addr = cpu_to_le32(addr);
+	cp.val = cpu_to_le32(val);
+	skb = __hci_cmd_sync(hdev, RTL_VSC_OP_WRITE_VENDOR, sizeof(cp), &cp, HCI_INIT_TIMEOUT);
+	if (IS_ERR(skb)) {
+		err = PTR_ERR(skb);
+		bt_dev_err(hdev, "RTL: Write mem32 failed (%d)", err);
+		return err;
+	}
+
+	kfree_skb(skb);
+	return 0;
+}
+
 static void *rtl_iov_pull_data(struct rtl_iovec *iov, u32 len)
 {
 	void *data = iov->data;
@@ -462,6 +528,31 @@ static void *rtl_iov_pull_data(struct rtl_iovec *iov, u32 len)
 	return data;
 }
 
+
+static void btrtl_insert_ordered_patch_image(struct rtl_section_patch_image *image,
+					     struct btrtl_device_info *btrtl_dev)
+{
+	struct list_head *pos;
+	struct list_head *next;
+	struct rtl_section_patch_image *node;
+
+	list_for_each_safe(pos, next, &btrtl_dev->patch_images) {
+		node = list_entry(pos, struct rtl_section_patch_image, list);
+
+		if (node->image_id > image->image_id) {
+			__list_add(&image->list, pos->prev, pos);
+			return;
+		}
+
+		if (node->image_id == image->image_id &&
+		    node->index > image->index) {
+			__list_add(&image->list, pos->prev, pos);
+			return;
+		}
+	}
+	__list_add(&image->list, pos->prev, pos);
+}
+
 static void btrtl_insert_ordered_subsec(struct rtl_subsection *node,
 					struct btrtl_device_info *btrtl_dev)
 {
@@ -633,6 +724,279 @@ static int rtlbt_parse_firmware_v2(struct hci_dev *hdev,
 	}
 
 	*_buf = ptr;
+	btrtl_dev->fw_type = FW_TYPE_V2;
+	return len;
+}
+
+static int rtlbt_parse_config(struct hci_dev *hdev,
+			      struct rtl_section_patch_image *patch_image,
+			      struct btrtl_device_info *btrtl_dev)
+{
+	const struct id_table *ic_info = NULL;
+	const struct firmware *fw;
+	char tmp_name[32];
+	char filename[64];
+	u8 *cfg_buf;
+	char *str;
+	char *p;
+	size_t len;
+	int ret;
+
+	if (btrtl_dev && btrtl_dev->ic_info)
+		ic_info = btrtl_dev->ic_info;
+
+	if (!ic_info)
+		return -EINVAL;
+
+	str = ic_info->cfg_name;
+	if (btrtl_dev->fw_type == FW_TYPE_V3_1) {
+		if (!patch_image->image_id && !patch_image->index) {
+			snprintf(filename, sizeof(filename), "%s.bin", str);
+			goto load_fw;
+		}
+		goto done;
+	}
+
+	len = strlen(str);
+	if (len > sizeof(tmp_name) - 1)
+		len = sizeof(tmp_name) - 1;
+	memcpy(tmp_name, str, len);
+	tmp_name[len] = '\0';
+
+	str = tmp_name;
+	p = strsep(&str, ".");
+
+	ret = snprintf(filename, sizeof(filename), "%s", p);
+	if (patch_image->config_rule && patch_image->need_config) {
+		switch (patch_image->image_id) {
+		case IMAGE_ID_F000:
+		case IMAGE_ID_F001:
+		case IMAGE_ID_F002:
+			ret += snprintf(filename + ret, sizeof(filename) - ret,
+					"_%04x", patch_image->image_id);
+			break;
+		default:
+			goto done;
+		}
+	} else {
+		goto done;
+	}
+
+	snprintf(filename + ret, sizeof(filename) - ret, ".%s", str ? str : "bin");
+
+load_fw:
+	rtl_dev_info(hdev, "config file: %s", filename);
+	ret = request_firmware(&fw, filename, &hdev->dev);
+	if (ret < 0) {
+		if (btrtl_dev->fw_type == FW_TYPE_V3_2) {
+			len = 4;
+			cfg_buf = kvmalloc(len, GFP_KERNEL);
+			if (!cfg_buf)
+				return -ENOMEM;
+
+			memset(cfg_buf, 0xff, len);
+			patch_image->cfg_buf = cfg_buf;
+			patch_image->cfg_len = len;
+			return 0;
+		}
+		goto err_req_fw;
+	}
+	rtl_dev_info(hdev, "config file: %s found", filename);
+	cfg_buf = kvmalloc(fw->size, GFP_KERNEL);
+	if (!cfg_buf) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	memcpy(cfg_buf, fw->data, fw->size);
+	len = fw->size;
+	release_firmware(fw);
+
+	patch_image->cfg_buf = cfg_buf;
+	patch_image->cfg_len = len;
+done:
+	return 0;
+err:
+	release_firmware(fw);
+err_req_fw:
+	rtl_dev_info(hdev, "config file: [%s] not found", filename);
+	return ret;
+}
+
+static int rtlbt_parse_section_v3(struct hci_dev *hdev,
+				  struct btrtl_device_info *btrtl_dev,
+				  u32 opcode, u8 *data, u32 len)
+{
+	struct rtl_section_patch_image *patch_image;
+	struct rtl_patch_image_hdr *hdr;
+	u16 image_id;
+	u16 chip_id;
+	size_t patch_image_len;
+	u8 *ptr;
+	int ret = 0;
+	size_t i;
+	struct rtl_iovec iov = {
+		.data = data,
+		.len  = len,
+	};
+
+	hdr = rtl_iov_pull_data(&iov, sizeof(*hdr));
+	if (!hdr)
+		return -EINVAL;
+
+	if (btrtl_dev->opcode && btrtl_dev->opcode != opcode) {
+		rtl_dev_err(hdev, "invalid opcode 0x%02x", opcode);
+		return -EINVAL;
+	}
+
+	if (!btrtl_dev->opcode) {
+		btrtl_dev->opcode = opcode;
+		switch (btrtl_dev->opcode) {
+		case RTL_PATCH_V3_1:
+			btrtl_dev->fw_type = FW_TYPE_V3_1;
+			break;
+		case RTL_PATCH_V3_2:
+			btrtl_dev->fw_type = FW_TYPE_V3_2;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	patch_image_len = (u32)le64_to_cpu(hdr->patch_image_len);
+	chip_id = le16_to_cpu(hdr->chip_id);
+	image_id = le16_to_cpu(hdr->image_id);
+	rtl_dev_info(hdev, "image (%04x:%02x), chip id %u, cut 0x%02x, len %08zx"
+		     , image_id, hdr->index, chip_id, hdr->ic_cut,
+		     patch_image_len);
+
+	if (btrtl_dev->key_id != hdr->key_id) {
+		rtl_dev_err(hdev, "invalid key_id (%u, %u)", hdr->key_id,
+			    btrtl_dev->key_id);
+		return -EINVAL;
+	}
+
+	if (hdr->ic_cut != btrtl_dev->rom_version + 1) {
+		rtl_dev_info(hdev, "unused ic_cut (%u, %u)", hdr->ic_cut,
+			    btrtl_dev->rom_version + 1);
+		return -EINVAL;
+	}
+
+	if (btrtl_dev->fw_type == FW_TYPE_V3_1 && !btrtl_dev->project_id)
+		btrtl_dev->project_id = chip_id;
+
+	if (btrtl_dev->fw_type == FW_TYPE_V3_2 &&
+	    chip_id != btrtl_dev->project_id) {
+		rtl_dev_err(hdev, "invalid chip_id (%u, %d)", chip_id,
+			    btrtl_dev->project_id);
+		return -EINVAL;
+	}
+
+	ptr = rtl_iov_pull_data(&iov, patch_image_len);
+	if (!ptr)
+		return -ENODATA;
+
+	patch_image = kzalloc_obj(*patch_image);
+	if (!patch_image)
+		return -ENOMEM;
+	patch_image->index = hdr->index;
+	patch_image->image_id = image_id;
+	patch_image->config_rule = hdr->config_rule;
+	patch_image->need_config = hdr->need_config;
+
+	for (i = 0; i < DL_FIX_ADDR_MAX; i++) {
+		patch_image->fix[i].addr =
+			(u32)le64_to_cpu(hdr->addr_fix[i * 2]);
+		patch_image->fix[i].value =
+			(u32)le64_to_cpu(hdr->addr_fix[i * 2 + 1]);
+	}
+
+	patch_image->image_len = patch_image_len;
+	patch_image->image_data = kvmalloc(patch_image_len, GFP_KERNEL);
+	if (!patch_image->image_data) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	memcpy(patch_image->image_data, ptr, patch_image_len);
+	patch_image->image_ver =
+		get_unaligned_le32(ptr + patch_image->image_len - 4);
+	rtl_dev_info(hdev, "image version: %08x", patch_image->image_ver);
+
+	rtlbt_parse_config(hdev, patch_image, btrtl_dev);
+
+	ret = patch_image->image_len;
+
+	btrtl_insert_ordered_patch_image(patch_image, btrtl_dev);
+
+	return ret;
+err:
+	kfree(patch_image);
+	return ret;
+}
+
+static int rtlbt_parse_firmware_v3(struct hci_dev *hdev,
+				   struct btrtl_device_info *btrtl_dev)
+{
+	struct rtl_epatch_header_v3 *hdr;
+	int rc;
+	u32 num_sections;
+	struct rtl_section_v3 *section;
+	u32 section_len;
+	u32 opcode;
+	int len = 0;
+	int i;
+	u8 *ptr;
+	struct rtl_iovec iov = {
+		.data = btrtl_dev->fw_data,
+		.len  = btrtl_dev->fw_len,
+	};
+
+	rtl_dev_info(hdev, "key id %u", btrtl_dev->key_id);
+
+	hdr = rtl_iov_pull_data(&iov, sizeof(*hdr));
+	if (!hdr)
+		return -EINVAL;
+	num_sections = le32_to_cpu(hdr->num_sections);
+
+	rtl_dev_dbg(hdev, "timpstamp %08x-%08x", *((u32 *)hdr->timestamp),
+		    *((u32 *)(hdr->timestamp + 4)));
+
+	for (i = 0; i < num_sections; i++) {
+		section = rtl_iov_pull_data(&iov, sizeof(*section));
+		if (!section)
+			break;
+
+		section_len = (u32)le64_to_cpu(section->len);
+		opcode = le32_to_cpu(section->opcode);
+
+		rtl_dev_dbg(hdev, "opcode 0x%04x", section->opcode);
+
+		ptr = rtl_iov_pull_data(&iov, section_len);
+		if (!ptr)
+			break;
+
+		rc = 0;
+		switch (opcode) {
+		case RTL_PATCH_V3_1:
+		case RTL_PATCH_V3_2:
+			rc = rtlbt_parse_section_v3(hdev, btrtl_dev, opcode,
+						    ptr, section_len);
+			break;
+		default:
+			rtl_dev_warn(hdev, "Unknown opcode %08x", opcode);
+			break;
+		}
+		if (rc < 0) {
+			rtl_dev_err(hdev, "Parse section (%u) err (%d)",
+				    opcode, rc);
+			continue;
+		}
+		len += rc;
+	}
+
+	rtl_dev_info(hdev, "image payload total len: 0x%08x", len);
+	if (!len)
+		return -ENODATA;
+
 	return len;
 }
 
@@ -678,6 +1042,9 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
 	if (btrtl_dev->fw_len <= 8)
 		return -EINVAL;
 
+	if (!memcmp(btrtl_dev->fw_data, RTL_EPATCH_SIGNATURE_V3, 8))
+		return rtlbt_parse_firmware_v3(hdev, btrtl_dev);
+
 	if (!memcmp(btrtl_dev->fw_data, RTL_EPATCH_SIGNATURE, 8))
 		min_size = sizeof(struct rtl_epatch_header) +
 				sizeof(extension_sig) + 3;
@@ -813,10 +1180,11 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
 	memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4);
 
 	*_buf = buf;
+	btrtl_dev->fw_type = FW_TYPE_V1;
 	return len;
 }
 
-static int rtl_download_firmware(struct hci_dev *hdev,
+static int rtl_download_firmware(struct hci_dev *hdev, u8 fw_type,
 				 const unsigned char *data, int fw_len)
 {
 	struct rtl_download_cmd *dl_cmd;
@@ -827,6 +1195,13 @@ static int rtl_download_firmware(struct hci_dev *hdev,
 	int j = 0;
 	struct sk_buff *skb;
 	struct hci_rp_read_local_version *rp;
+	u8 dl_rp_len = sizeof(struct rtl_download_response);
+
+	if (is_v3_fw(fw_type)) {
+		j = 1;
+		if (fw_type == FW_TYPE_V3_2)
+			dl_rp_len++;
+	}
 
 	dl_cmd = kmalloc_obj(*dl_cmd);
 	if (!dl_cmd)
@@ -840,15 +1215,15 @@ static int rtl_download_firmware(struct hci_dev *hdev,
 			j = 1;
 
 		if (i == (frag_num - 1)) {
-			dl_cmd->index |= 0x80; /* data end */
+			if (!is_v3_fw(fw_type))
+				dl_cmd->index |= 0x80; /* data end */
 			frag_len = fw_len % RTL_FRAG_LEN;
 		}
 		rtl_dev_dbg(hdev, "download fw (%d/%d). index = %d", i,
 				frag_num, dl_cmd->index);
 		memcpy(dl_cmd->data, data, frag_len);
 
-		/* Send download command */
-		skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
+		skb = __hci_cmd_sync(hdev, RTL_VSC_OP_DOWNLOAD_CMD, frag_len + 1, dl_cmd,
 				     HCI_INIT_TIMEOUT);
 		if (IS_ERR(skb)) {
 			rtl_dev_err(hdev, "download fw command failed (%ld)",
@@ -857,7 +1232,7 @@ static int rtl_download_firmware(struct hci_dev *hdev,
 			goto out;
 		}
 
-		if (skb->len != sizeof(struct rtl_download_response)) {
+		if (skb->len != dl_rp_len) {
 			rtl_dev_err(hdev, "download fw event length mismatch");
 			kfree_skb(skb);
 			ret = -EIO;
@@ -868,6 +1243,9 @@ static int rtl_download_firmware(struct hci_dev *hdev,
 		data += RTL_FRAG_LEN;
 	}
 
+	if (is_v3_fw(fw_type))
+		goto out;
+
 	skb = btrtl_read_local_version(hdev);
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
@@ -885,6 +1263,237 @@ static int rtl_download_firmware(struct hci_dev *hdev,
 	return ret;
 }
 
+static int rtl_check_download_state(struct hci_dev *hdev,
+				    struct btrtl_device_info *btrtl_dev)
+{
+	struct sk_buff *skb;
+	int ret = 0;
+	u8 *state;
+
+	skb = __hci_cmd_sync(hdev, RTL_VSC_OP_CHECK_DOWNLOAD_STATE, 0, NULL, HCI_CMD_TIMEOUT);
+	if (IS_ERR(skb)) {
+		rtl_dev_err(hdev, "write tb error %lu", PTR_ERR(skb));
+		return -EIO;
+	}
+
+	/* Other driver might be downloading the combined firmware. */
+	state = skb_pull_data(skb, sizeof(*state));
+	if (state && *state == 0x03) {
+		btrealtek_set_flag(hdev, REALTEK_DOWNLOADING);
+		ret = btrealtek_wait_on_flag_timeout(hdev, REALTEK_DOWNLOADING,
+						     TASK_INTERRUPTIBLE,
+						     msecs_to_jiffies(5000));
+		if (ret == -EINTR) {
+			bt_dev_err(hdev, "Firmware loading interrupted");
+			goto out;
+		}
+
+		if (ret) {
+			bt_dev_err(hdev, "Firmware loading timeout");
+			ret = -ETIMEDOUT;
+		} else {
+			ret = -EALREADY;
+		}
+
+	}
+
+out:
+	kfree_skb(skb);
+	return ret;
+}
+
+static int rtl_finalize_download(struct hci_dev *hdev,
+				 struct btrtl_device_info *btrtl_dev)
+{
+	struct hci_rp_read_local_version *rp_ver;
+	u8 params[2] = { 0x03, 0xb2 };
+	struct sk_buff *skb;
+	int ret = 0;
+	u16 opcode;
+	u32 len;
+	u8 *p;
+
+	opcode = RTL_VSC_OP_WDG_RESET_CMD;
+	len = 2;
+	if (btrtl_dev->opcode == RTL_PATCH_V3_1) {
+		opcode = RTL_VSC_OP_DOWNLOAD_CMD;
+		params[0] = 0x80;
+		len = 1;
+	}
+	skb = __hci_cmd_sync(hdev, opcode, len, params, HCI_CMD_TIMEOUT);
+	if (IS_ERR(skb)) {
+		rtl_dev_err(hdev, "Watchdog reset err (%ld)", PTR_ERR(skb));
+		return -EIO;
+	}
+	p = skb_pull_data(skb, 1);
+	if (!p) {
+		ret = -ENODATA;
+		goto out;
+	}
+	rtl_dev_info(hdev, "Watchdog reset status %02x", *p);
+	kfree_skb(skb);
+
+	skb = btrtl_read_local_version(hdev);
+	if (IS_ERR(skb)) {
+		ret = PTR_ERR(skb);
+		rtl_dev_err(hdev, "read local version failed (%d)", ret);
+		return ret;
+	}
+
+	rp_ver = skb_pull_data(skb, sizeof(*rp_ver));
+	if (rp_ver)
+		rtl_dev_info(hdev, "fw version 0x%04x%04x",
+			     __le16_to_cpu(rp_ver->hci_rev),
+			     __le16_to_cpu(rp_ver->lmp_subver));
+out:
+	kfree_skb(skb);
+	return ret;
+}
+
+static int rtl_security_check(struct hci_dev *hdev,
+			      struct btrtl_device_info *btrtl_dev)
+{
+	struct rtl_section_patch_image *tmp = NULL;
+	struct rtl_section_patch_image *image = NULL;
+	u32 val;
+	int ret;
+
+	list_for_each_entry_reverse(tmp, &btrtl_dev->patch_images, list) {
+		/* Check security hdr */
+		if (!tmp->fix[DL_FIX_SEC_HDR_ADDR].value ||
+		    !tmp->fix[DL_FIX_SEC_HDR_ADDR].addr ||
+		    tmp->fix[DL_FIX_SEC_HDR_ADDR].addr == 0xffffffff)
+			continue;
+		rtl_dev_info(hdev, "addr 0x%08x, value 0x%08x",
+			     tmp->fix[DL_FIX_SEC_HDR_ADDR].addr,
+			     tmp->fix[DL_FIX_SEC_HDR_ADDR].value);
+		image = tmp;
+		break;
+	}
+
+	if (!image)
+		return 0;
+
+	rtl_dev_info(hdev, "sec image (%04x:%02x)", image->image_id,
+		     image->index);
+	val = image->fix[DL_FIX_PATCH_ADDR].value + image->image_len -
+					image->fix[DL_FIX_SEC_HDR_ADDR].value;
+	ret = btrtl_vendor_write_mem(hdev, image->fix[DL_FIX_PATCH_ADDR].addr,
+				     val);
+	if (ret) {
+		rtl_dev_err(hdev, "write sec reg failed (%d)", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int rtl_download_firmware_v3(struct hci_dev *hdev,
+				    struct btrtl_device_info *btrtl_dev)
+{
+	struct rtl_section_patch_image *image, *tmp;
+	struct rtl_rp_dl_v3 *rp;
+	struct sk_buff *skb;
+	u8 *fw_data;
+	int fw_len;
+	int ret = 0;
+	u8 i;
+
+	if (btrtl_dev->fw_type == FW_TYPE_V3_2) {
+		ret = rtl_check_download_state(hdev, btrtl_dev);
+		if (ret) {
+			if (ret == -EALREADY)
+				return 0;
+			return ret;
+		}
+	}
+
+	list_for_each_entry_safe(image, tmp, &btrtl_dev->patch_images, list) {
+		rtl_dev_dbg(hdev, "image (%04x:%02x)", image->image_id,
+			    image->index);
+
+		for (i = DL_FIX_CI_ID; i < DL_FIX_ADDR_MAX; i++) {
+			if (!image->fix[i].addr ||
+			    image->fix[i].addr == 0xffffffff) {
+				rtl_dev_dbg(hdev, "no need to write addr %08x",
+					    image->fix[i].addr);
+				continue;
+			}
+			rtl_dev_dbg(hdev, "write addr and val, 0x%08x, 0x%08x",
+				    image->fix[i].addr, image->fix[i].value);
+			if (btrtl_vendor_write_mem(hdev, image->fix[i].addr,
+						   image->fix[i].value)) {
+				rtl_dev_err(hdev, "write reg failed");
+				ret = -EIO;
+				goto done;
+			}
+		}
+
+		fw_len = image->image_len + image->cfg_len;
+		fw_data = kvmalloc(fw_len, GFP_KERNEL);
+		if (!fw_data) {
+			rtl_dev_err(hdev, "Couldn't alloc buf for image data");
+			ret = -ENOMEM;
+			goto done;
+		}
+		memcpy(fw_data, image->image_data, image->image_len);
+		if (image->cfg_len > 0)
+			memcpy(fw_data + image->image_len, image->cfg_buf,
+			       image->cfg_len);
+
+		rtl_dev_dbg(hdev, "patch image (%04x:%02x). len: %d",
+			    image->image_id, image->index, fw_len);
+		rtl_dev_dbg(hdev, "fw_data %p, image buf %p, len %u", fw_data,
+			    image->image_data, image->image_len);
+
+		ret = rtl_download_firmware(hdev, btrtl_dev->fw_type, fw_data,
+					    fw_len);
+		kvfree(fw_data);
+		if (ret < 0) {
+			rtl_dev_err(hdev, "download firmware failed (%d)", ret);
+			goto done;
+		}
+
+		if (image->list.next != &btrtl_dev->patch_images &&
+		    image->image_id == tmp->image_id)
+			continue;
+
+		if (btrtl_dev->fw_type == FW_TYPE_V3_1)
+			continue;
+
+		i = 0x80;
+		skb = __hci_cmd_sync(hdev, RTL_VSC_OP_DOWNLOAD_CMD, 1, &i, HCI_CMD_TIMEOUT);
+		if (IS_ERR(skb)) {
+			ret = -EIO;
+			rtl_dev_err(hdev, "Failed to issue last cmd fc20, %ld",
+				    PTR_ERR(skb));
+			goto done;
+		}
+		ret = 2;
+		rp = skb_pull_data(skb, sizeof(*rp));
+		if (rp)
+			ret = rp->err;
+		kfree_skb(skb);
+		if (ret == 2) {
+			/* Verification failure */
+			ret = -EFAULT;
+			goto done;
+		}
+	}
+
+	if (btrtl_dev->fw_type == FW_TYPE_V3_1) {
+		ret = rtl_security_check(hdev, btrtl_dev);
+		if (ret) {
+			rtl_dev_err(hdev, "Security check failed (%d)", ret);
+			goto done;
+		}
+	}
+
+	ret = rtl_finalize_download(hdev, btrtl_dev);
+
+done:
+	return ret;
+}
+
 static int rtl_load_file(struct hci_dev *hdev, const char *name, u8 **buff)
 {
 	const struct firmware *fw;
@@ -918,7 +1527,7 @@ static int btrtl_setup_rtl8723a(struct hci_dev *hdev,
 		return -EINVAL;
 	}
 
-	return rtl_download_firmware(hdev, btrtl_dev->fw_data,
+	return rtl_download_firmware(hdev, FW_TYPE_V0, btrtl_dev->fw_data,
 				     btrtl_dev->fw_len);
 }
 
@@ -933,7 +1542,7 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev,
 	if (ret < 0)
 		goto out;
 
-	if (btrtl_dev->cfg_len > 0) {
+	if (!is_v3_fw(btrtl_dev->fw_type) && btrtl_dev->cfg_len > 0) {
 		tbuff = kvzalloc(ret + btrtl_dev->cfg_len, GFP_KERNEL);
 		if (!tbuff) {
 			ret = -ENOMEM;
@@ -949,9 +1558,14 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev,
 		fw_data = tbuff;
 	}
 
+	if (is_v3_fw(btrtl_dev->fw_type)) {
+		ret = rtl_download_firmware_v3(hdev, btrtl_dev);
+		goto out;
+	}
+
 	rtl_dev_info(hdev, "cfg_sz %d, total sz %d", btrtl_dev->cfg_len, ret);
 
-	ret = rtl_download_firmware(hdev, fw_data, ret);
+	ret = rtl_download_firmware(hdev, btrtl_dev->fw_type, fw_data, ret);
 
 out:
 	kvfree(fw_data);
@@ -1021,7 +1635,7 @@ static int rtl_read_chip_type(struct hci_dev *hdev, u8 *type)
 	const unsigned char cmd_buf[] = {0x00, 0x94, 0xa0, 0x00, 0xb0};
 
 	/* Read RTL chip type command */
-	skb = __hci_cmd_sync(hdev, 0xfc61, 5, cmd_buf, HCI_INIT_TIMEOUT);
+	skb = __hci_cmd_sync(hdev, RTL_VSC_OP_READ_VENDER, 5, cmd_buf, HCI_INIT_TIMEOUT);
 	if (IS_ERR(skb)) {
 		rtl_dev_err(hdev, "Read chip type failed (%ld)",
 			    PTR_ERR(skb));
@@ -1047,6 +1661,7 @@ static int rtl_read_chip_type(struct hci_dev *hdev, u8 *type)
 void btrtl_free(struct btrtl_device_info *btrtl_dev)
 {
 	struct rtl_subsection *entry, *tmp;
+	struct rtl_section_patch_image *image, *next;
 
 	kvfree(btrtl_dev->fw_data);
 	kvfree(btrtl_dev->cfg_data);
@@ -1056,6 +1671,13 @@ void btrtl_free(struct btrtl_device_info *btrtl_dev)
 		kfree(entry);
 	}
 
+	list_for_each_entry_safe(image, next, &btrtl_dev->patch_images, list) {
+		list_del(&image->list);
+		kvfree(image->image_data);
+		kvfree(image->cfg_buf);
+		kfree(image);
+	}
+
 	kfree(btrtl_dev);
 }
 EXPORT_SYMBOL_GPL(btrtl_free);
@@ -1063,7 +1685,7 @@ EXPORT_SYMBOL_GPL(btrtl_free);
 struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 					   const char *postfix)
 {
-	struct btrealtek_data *coredump_info = hci_get_priv(hdev);
+	struct btrealtek_data *btrtl_data  = hci_get_priv(hdev);
 	struct btrtl_device_info *btrtl_dev;
 	struct sk_buff *skb;
 	struct hci_rp_read_local_version *resp;
@@ -1072,6 +1694,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 	char cfg_name[40];
 	u16 hci_rev, lmp_subver;
 	u8 hci_ver, lmp_ver, chip_type = 0;
+	u8 chip_id = 0;
 	int ret;
 	int rc;
 	u8 key_id;
@@ -1084,8 +1707,15 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 	}
 
 	INIT_LIST_HEAD(&btrtl_dev->patch_subsecs);
+	INIT_LIST_HEAD(&btrtl_dev->patch_images);
 
 check_version:
+	ret = btrtl_read_chip_id(hdev, &chip_id);
+	if (!ret && chip_id >= CHIP_ID_V3_BASE) {
+		btrtl_dev->project_id = chip_id;
+		goto read_local_ver;
+	}
+
 	ret = btrtl_vendor_read_reg16(hdev, RTL_CHIP_SUBVER, reg_val);
 	if (ret < 0)
 		goto err_free;
@@ -1108,6 +1738,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 		}
 	}
 
+read_local_ver:
 	skb = btrtl_read_local_version(hdev);
 	if (IS_ERR(skb)) {
 		ret = PTR_ERR(skb);
@@ -1185,7 +1816,11 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 		goto err_free;
 	}
 
-	rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ, reg_val);
+	if (btrtl_dev->project_id >= CHIP_ID_V3_BASE)
+		rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ_V3, reg_val);
+	else
+		rc = btrtl_vendor_read_reg16(hdev, RTL_SEC_PROJ_V2, reg_val);
+
 	if (rc < 0)
 		goto err_free;
 
@@ -1243,7 +1878,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 		hci_set_msft_opcode(hdev, 0xFCF0);
 
 	if (btrtl_dev->ic_info)
-		coredump_info->rtl_dump.controller = btrtl_dev->ic_info->hw_info;
+		btrtl_data->rtl_dump.controller = btrtl_dev->ic_info->hw_info;
 
 	return btrtl_dev;
 
@@ -1416,6 +2051,35 @@ int btrtl_shutdown_realtek(struct hci_dev *hdev)
 }
 EXPORT_SYMBOL_GPL(btrtl_shutdown_realtek);
 
+
+int btrtl_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
+	struct hci_event_hdr *hdr;
+	u8 *p;
+
+	if (!clone)
+		goto out;
+
+	hdr = skb_pull_data(clone, sizeof(*hdr));
+	if (!hdr || hdr->evt != HCI_VENDOR_PKT)
+		goto out;
+
+	p = skb_pull_data(clone, 1);
+	if (!p)
+		goto out;
+	switch (*p) {
+	case 0x77:
+		if (btrealtek_test_and_clear_flag(hdev, REALTEK_DOWNLOADING))
+			btrealtek_wake_up_flag(hdev, REALTEK_DOWNLOADING);
+		break;
+	}
+out:
+	consume_skb(clone);
+	return hci_recv_frame(hdev, skb);
+}
+EXPORT_SYMBOL_GPL(btrtl_recv_event);
+
 static unsigned int btrtl_convert_baudrate(u32 device_baudrate)
 {
 	switch (device_baudrate) {
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
index a2d9d34f9fb0..dd4acdf29b2f 100644
--- a/drivers/bluetooth/btrtl.h
+++ b/drivers/bluetooth/btrtl.h
@@ -12,6 +12,19 @@
 #define rtl_dev_info(dev, fmt, ...) bt_dev_info(dev, "RTL: " fmt, ##__VA_ARGS__)
 #define rtl_dev_dbg(dev, fmt, ...) bt_dev_dbg(dev, "RTL: " fmt, ##__VA_ARGS__)
 
+#define FW_TYPE_V0		0
+#define FW_TYPE_V1		1
+#define FW_TYPE_V2		2
+#define FW_TYPE_V3_1		3
+#define FW_TYPE_V3_2		4
+#define is_v3_fw(type)	(type == FW_TYPE_V3_1 || type == FW_TYPE_V3_2)
+
+#define DL_FIX_CI_ID		0
+#define DL_FIX_CI_ADDR		1
+#define DL_FIX_PATCH_ADDR	2
+#define DL_FIX_SEC_HDR_ADDR	3
+#define DL_FIX_ADDR_MAX		4
+
 struct btrtl_device_info;
 
 struct rtl_chip_type_evt {
@@ -103,8 +116,79 @@ struct rtl_vendor_cmd {
 	__u8 param[5];
 } __packed;
 
+struct rtl_vendor_write_cmd {
+	u8 type;
+	__le32 addr;
+	__le32 val;
+} __packed;
+
+struct rtl_rp_read_chip_id {
+	__u8 status;
+	__u8 chip_id;
+} __packed;
+
+struct rtl_rp_dl_v3 {
+	__u8 status;
+	__u8 index;
+	__u8 err;
+} __packed;
+
+struct rtl_epatch_header_v3 {
+	__u8 signature[8];
+	__u8 timestamp[8];
+	__le32 ver_rsvd;
+	__le32 num_sections;
+} __packed;
+
+struct rtl_section_v3 {
+	__le32 opcode;
+	__le64 len;
+	u8 data[];
+} __packed;
+
+struct rtl_addr_fix {
+	u32 addr;
+	u32 value;
+};
+
+struct rtl_section_patch_image {
+	u16 image_id;
+	u8 index;
+	u8 config_rule;
+	u8 need_config;
+
+	struct rtl_addr_fix fix[DL_FIX_ADDR_MAX];
+
+	u32 image_len;
+	u8 *image_data;
+	u32 image_ver;
+
+	u8  *cfg_buf;
+	u16 cfg_len;
+
+	struct list_head list;
+};
+
+struct rtl_patch_image_hdr {
+	__le16 chip_id;
+	u8 ic_cut;
+	u8 key_id;
+	u8 enable_ota;
+	__le16 image_id;
+	u8 config_rule;
+	u8 need_config;
+	u8 rsv[950];
+
+	__le64 addr_fix[DL_FIX_ADDR_MAX * 2];
+	u8 index;
+
+	__le64 patch_image_len;
+	__u8 data[];
+} __packed;
+
 enum {
 	REALTEK_ALT6_CONTINUOUS_TX_CHIP,
+	REALTEK_DOWNLOADING,
 
 	__REALTEK_NUM_FLAGS,
 };
@@ -130,8 +214,20 @@ struct btrealtek_data {
 #define btrealtek_get_flag(hdev)					\
 	(((struct btrealtek_data *)hci_get_priv(hdev))->flags)
 
+#define btrealtek_wake_up_flag(hdev, nr)				\
+	do {								\
+		struct btrealtek_data *rtl = hci_get_priv((hdev));	\
+		wake_up_bit(rtl->flags, (nr));				\
+	} while (0)
+
 #define btrealtek_test_flag(hdev, nr)	test_bit((nr), btrealtek_get_flag(hdev))
 
+#define btrealtek_test_and_clear_flag(hdev, nr)				\
+		test_and_clear_bit((nr), btrealtek_get_flag(hdev))
+
+#define btrealtek_wait_on_flag_timeout(hdev, nr, m, to)			\
+		wait_on_bit_timeout(btrealtek_get_flag(hdev), (nr), m, to)
+
 #if IS_ENABLED(CONFIG_BT_RTL)
 
 struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
@@ -148,6 +244,7 @@ int btrtl_get_uart_settings(struct hci_dev *hdev,
 			    unsigned int *controller_baudrate,
 			    u32 *device_baudrate, bool *flow_control);
 void btrtl_set_driver_name(struct hci_dev *hdev, const char *driver_name);
+int btrtl_recv_event(struct hci_dev *hdev, struct sk_buff *skb);
 
 #else
 
@@ -157,6 +254,11 @@ static inline struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
 	return ERR_PTR(-EOPNOTSUPP);
 }
 
+static inline int btrtl_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline void btrtl_free(struct btrtl_device_info *btrtl_dev)
 {
 }
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 572091e601f9..96fcf09e0b7f 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2787,6 +2787,9 @@ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
 		return 0;
 	}
 
+	if (skb->data[0] == HCI_VENDOR_PKT)
+		return btrtl_recv_event(hdev, skb);
+
 	return hci_recv_frame(hdev, skb);
 }
 
-- 
2.34.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox