* [PATCH 0/2] Bluetooth: SMP: distribute the identity address when bonding
@ 2026-10-24 11:24 Brandon Williams
2026-10-24 11:24 ` [PATCH 1/2] Bluetooth: SMP: ignore an all-zero IRK Brandon Williams
2026-10-24 11:24 ` [PATCH 2/2] Bluetooth: SMP: distribute the identity address when bonding Brandon Williams
0 siblings, 2 replies; 3+ messages in thread
From: Brandon Williams @ 2026-10-24 11:24 UTC (permalink / raw)
To: linux-bluetooth
Cc: Marcel Holtmann, Luiz Augusto von Dentz, linux-kernel, Brandon Williams
The Microsoft Surface Slim Pen 2 bonds with the host through its dock
(LE legacy pairing with out-of-band data) and afterwards only advertises
to reconnect, when its button is pressed, if the host distributed its
identity during pairing. Linux only distributes its identity with
privacy enabled, and with privacy the host scans and connects from
resolvable private addresses while the pen directs its advertisements at
the host's public address, so a pen bonded by Linux never reconnects.
Patch 2 makes Linux offer its identity key whenever it bonds over LE.
Without privacy that is an all-zero IRK, which the specification defines
as "no valid resolvable private address", and the public or static
identity address. Patch 1 comes first so that Linux, as a receiver, does
not store the all-zero IRKs that other Linux hosts then send.
Patch 2 changes the Pairing Requests that smp-tester checks: four client
tests expect the old initiator key distribution. "[PATCH BlueZ 1/2]
smp-tester: Expect the identity key in Pairing Requests" updates them,
and "[PATCH BlueZ 2/2] smp-tester: Add identity key distribution tests"
adds a test for each patch. Until those are applied, smp-tester in CI
will report the four client tests as failed.
Choices a reviewer may ask about:
- Why not distribute a real IRK without privacy? The host then never
uses a resolvable private address, so there is nothing for an IRK to
resolve, and the all-zero IRK is the specification's way to say so.
- Who now learns our identity address? Every LE device we bond with that
asks for it. Without privacy that is the address we already advertise
and connect from, so nothing new is disclosed.
- Devices that do not want our identity key do not get it: the Pairing
Response masks the initiator key distribution down to what the
responder accepts.
- Why drop an all-zero IRK instead of storing it and skipping it during
resolution? Treating the peer as one that distributed no identity key
keeps the key out of both host resolution and the controller's
resolving list, where it could only mean "accept the identity
address", which the controller does for a peer without an entry too.
- No Fixes tags: patch 1 is hardening and patch 2 a change of behaviour;
neither is meant for stable.
- If you would rather keep the current default, patch 2 can instead be
an opt-in setting that bluetoothd enables; I am happy to rework it
that way.
Testing:
- On bluetooth-next 47d4d9f67e92 under QEMU (arm64, TCG) with KASAN,
PROVE_LOCKING, PROVE_RCU and DEBUG_ATOMIC_SLEEP, with the BlueZ
patches: smp-tester passes 10/10 tests in each of 10 runs; without
these patches the four updated client tests and both new tests fail.
mgmt-tester (514 of 515, "Set powered on - Blocked by rfkill" skips
itself as the test kernel has no /dev/rfkill) and l2cap-tester
(111/111) give the same results with and without them. No KASAN,
lockdep or RCU reports. sparse and W=1 are clean for smp.o;
checkpatch --strict is clean. The emulator runs used the same code
before a comment in patch 1 was reworded.
- Hardware: both patches have run on a Surface Pro 11 (X1E80100,
WCN7850) since 2026-10-13, backported to 7.2.8 and 7.3. The Slim Pen 2
reconnects on a single click, double click and press-and-hold, and the
Surface Pro Flex Keyboard pairs over its out-of-band path, accepts our
identity key and reconnects.
- Other LE devices, on the same Surface Pro 11 with privacy off, each
bonding over LE from scratch: a Corne keyboard running ZMK (Zephyr), a
Logitech Lift mouse, a Samsung Galaxy Z Fold8 and an iPhone, the two
phones once with each side initiating (nRF Connect and LightBlue
advertising or connecting). All of them accepted our identity key, all
but the Corne sent their own IRK, which was stored, and all bonded with
no Pairing Failed. The Corne reconnects on its own, the Lift after a
power cycle and the Fold after its Bluetooth is turned off and on, and
the keyboards, mouse and pen after bluetoothd restarts, all with their
stored keys. The phones also derived the BR/EDR link key as before,
and the Fold connected over BR/EDR with it.
This is not a security issue: patch 2 discloses only the address already
used on air, and the all-zero IRK in patch 1 only lets a device pose as
a peer that uses its identity address in the clear anyway.
Tool use: the patches, their changelogs and the BlueZ tests were written
with an AI coding assistant (Claude Code, Claude Opus 5.5) in a session
that I directed: working out from HCI traces of Windows and Linux why
the pen did not reconnect, writing the patches and tests, and running
the emulator and hardware tests above. A review of the first version
found that Linux stored the all-zero IRK it would then receive from
other Linux hosts, which patch 1 fixes.
I found this with my own Slim Pen 2 and ran the device tests above myself,
pairing each of those devices with my Surface Pro 11. I have read both patches
and understand why patch 1 has to come first, and why sending an all-zero IRK
only shares the address we already use on air.
Brandon Williams (2):
Bluetooth: SMP: ignore an all-zero IRK
Bluetooth: SMP: distribute the identity address when bonding
net/bluetooth/smp.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
base-commit: 47d4d9f67e92d56ef3965f2727f9c98a5a611368
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] Bluetooth: SMP: ignore an all-zero IRK
2026-10-24 11:24 [PATCH 0/2] Bluetooth: SMP: distribute the identity address when bonding Brandon Williams
@ 2026-10-24 11:24 ` Brandon Williams
2026-10-24 11:24 ` [PATCH 2/2] Bluetooth: SMP: distribute the identity address when bonding Brandon Williams
1 sibling, 0 replies; 3+ messages in thread
From: Brandon Williams @ 2026-10-24 11:24 UTC (permalink / raw)
To: linux-bluetooth
Cc: Marcel Holtmann, Luiz Augusto von Dentz, linux-kernel, Brandon Williams
An all-zero Identity Resolving Key "indicates that a device does not
have a valid resolvable private address" (Core Specification, Vol 3,
Part H, 3.6.4), and a controller given an all-zero peer IRK in its
resolving list accepts only the peer's identity address (Vol 6, Part B,
4.7).
smp_cmd_ident_addr_info() stores such a key like any other, and
hci_find_irk_by_rpa() then resolves addresses against it in the host.
As the key is known to everyone, any device can generate resolvable
private addresses that the host reports as the bonded peer.
Treat an all-zero IRK as if no identity key had been distributed: do
not store it, and keep the peer's other keys under its connection
address.
Assisted-by: LLM
Signed-off-by: Brandon Williams <turbine.bmw@gmail.com>
---
net/bluetooth/smp.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 984b2d0b5e3e..fc75cf568471 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -2624,6 +2624,16 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
goto distribute;
}
+ /* An all-zero IRK means the peer has no resolvable private address
+ * (Core Specification, Vol 3, Part H, 3.6.4). The key is known to
+ * everyone, so storing it would let any device pose as this peer
+ * with resolvable private addresses generated from it.
+ */
+ if (!memchr_inv(smp->irk, 0, sizeof(smp->irk))) {
+ bt_dev_dbg(hcon->hdev, "ignoring all-zero IRK");
+ goto distribute;
+ }
+
bacpy(&smp->id_addr, &info->bdaddr);
smp->id_addr_type = info->addr_type;
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 2/2] Bluetooth: SMP: distribute the identity address when bonding
2026-10-24 11:24 [PATCH 0/2] Bluetooth: SMP: distribute the identity address when bonding Brandon Williams
2026-10-24 11:24 ` [PATCH 1/2] Bluetooth: SMP: ignore an all-zero IRK Brandon Williams
@ 2026-10-24 11:24 ` Brandon Williams
1 sibling, 0 replies; 3+ messages in thread
From: Brandon Williams @ 2026-10-24 11:24 UTC (permalink / raw)
To: linux-bluetooth
Cc: Marcel Holtmann, Luiz Augusto von Dentz, linux-kernel, Brandon Williams
build_pairing_cmd() only offers our Identity Information and Identity
Address Information when privacy is enabled. Without privacy the peer
never learns our identity address, and bonds without it.
Some peripherals need it. The Microsoft Surface Slim Pen 2 only
advertises to reconnect, after a button press, if the host it bonded
with distributed its identity, as Windows does. Paired by Linux, the pen
stays silent. Enabling privacy is no workaround: the host then scans and
connects from a resolvable private address, while the pen directs its
advertisements at the host's public address.
Offer the identity key whenever we bond over LE. Without privacy,
hdev->irk is all zeros, which "indicates that a device does not have a
valid resolvable private address" (Core Specification, Vol 3, Part H,
3.6.4), so the peer receives our public or static identity address and
no usable IRK; the previous patch makes Linux ignore such an IRK. The
peer still decides: the Pairing Response masks the distribution down to
what it accepts. Cross-transport key derivation over BR/EDR is
unchanged.
Tested on a Microsoft Surface Pro 11 (X1E80100, WCN7850): the Slim Pen 2
now accepts our identity key, and reconnects on a single click, double
click and press-and-hold after it has dropped the link. The Surface Pro
Flex Keyboard also accepts our identity key over its out-of-band pairing
and still reconnects.
Assisted-by: LLM
Signed-off-by: Brandon Williams <turbine.bmw@gmail.com>
---
net/bluetooth/smp.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index fc75cf568471..8ce5f92d7ee5 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -636,7 +636,13 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
u8 local_dist = 0, remote_dist = 0, oob_flag = SMP_OOB_NOT_PRESENT;
if (hci_dev_test_flag(hdev, HCI_BONDABLE)) {
- local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
+ /* Always distribute our identity address when bonding, so the
+ * peer can tell who it is bonded with. Without privacy the IRK
+ * sent along with it is all zeros, which the specification
+ * defines as having no resolvable private address. Some
+ * peripherals only reconnect to hosts that did this.
+ */
+ local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN | SMP_DIST_ID_KEY;
remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
authreq |= SMP_AUTH_BONDING;
} else {
--
2.56.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-24 11:25 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-24 11:24 [PATCH 0/2] Bluetooth: SMP: distribute the identity address when bonding Brandon Williams
2026-10-24 11:24 ` [PATCH 1/2] Bluetooth: SMP: ignore an all-zero IRK Brandon Williams
2026-10-24 11:24 ` [PATCH 2/2] Bluetooth: SMP: distribute the identity address when bonding Brandon Williams
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®