All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philipp Dunkel <noreply@github.com>
To: linux-bluetooth@vger.kernel.org
Subject: [bluez/bluez] 45fc10: shared/att: don't auto-bond on reactive elevation
Date: Sat, 18 Jul 2026 13:25:18 -0700	[thread overview]
Message-ID: <bluez/bluez/push/refs/heads/1130150/000000-4df3db@github.com> (raw)

  Branch: refs/heads/1130150
  Home:   https://github.com/bluez/bluez
  Commit: 45fc1030b964091e556343571b76be0ca64be664
      https://github.com/bluez/bluez/commit/45fc1030b964091e556343571b76be0ca64be664
  Author: Philipp Dunkel <pip@pipobscure.com>
  Date:   2026-07-18 (Sat, 18 Jul 2026)

  Changed paths:
    M src/device.c
    M src/shared/att.c
    M src/shared/att.h

  Log Message:
  -----------
  shared/att: don't auto-bond on reactive elevation

When bluetoothd connects to a freshly discovered LE peer it probes it as
a GATT client through its built-in profiles (battery, mcp, ...). If one
of those reads a characteristic the peer has protected, the peer answers
with Insufficient Authentication (0x05). change_security() reacts to that
error by raising BT_SECURITY on the ATT socket, and on an unbonded LE
link raising security starts SMP pairing.

The result is a bond that nobody asked for: no user, no agent, and no
application requested it. It logs as a device_bonding_complete() bond
with a (nil) requestor, and the user is shown a pairing prompt for a
device that merely came into range and connected. On phones and laptops
that expose authentication-gated GATT characteristics this fires on
essentially every connection.

The existing opt-out cannot prevent it. change_security() only returns
early when chan->sec_level != BT_ATT_SECURITY_AUTO, but
bt_att_chan_set_security() records sec_level solely for BT_ATT_LOCAL
channels. An L2CAP/LE channel keeps its zero-initialised value (AUTO)
for its entire lifetime, so the guard never triggers and the link
always elevates.

Add bt_att_set_no_auto_sec(), a per-bt_att flag that makes
change_security() refuse to elevate. Set it from gatt_client_init() for
any connection that is neither bonded nor in a requested bonding, so a
speculative profile probe that hits an authentication-protected
characteristic fails on the auth error instead of silently pairing.

Devices being bonded via Pair() are unaffected: device->bonding is set
before the connection is established, so gatt_client_init() takes the
existing elevate-for-bonding branch and never sets the flag. Already
bonded devices are unaffected too: they are elevated proactively at
attach time when their LTK is available, and reconnections see
device_is_bonded() and skip the flag.

Tested against Android (Galaxy Z Flip 4), iOS (iPhone) and macOS
(MacBook): each connects and is probed by the built-in profiles with no
unsolicited pairing prompt, while explicit pairing continues to work.

Assisted-by: Claude:Opus-4.8
AI disclosure: this change was developed with the assistance of an AI
model (Claude Opus 4.8). The author reviewed every line. The fix was
built and exercised on real hardware -- against Android (Galaxy Z Flip
4), iOS (iPhone) and macOS (MacBook) peers -- and its behaviour was
observed directly, not inferred.


  Commit: 4df3db7680e9da534458880a0b8a778a559a610f
      https://github.com/bluez/bluez/commit/4df3db7680e9da534458880a0b8a778a559a610f
  Author: Philipp Dunkel <pip@pipobscure.com>
  Date:   2026-07-18 (Sat, 18 Jul 2026)

  Changed paths:
    M unit/test-gatt.c

  Log Message:
  -----------
  unit/test-gatt: cover no-auto-sec on auth error

Add a regression test for bt_att_set_no_auto_sec(). The client reads a
characteristic and the peer answers with Insufficient Authentication
(0x05). Security is armed to BT_ATT_SECURITY_AUTO so a reactive elevation
would normally fire and retry the read, but no_auto_sec is set, so the
error must instead be delivered to the caller with no second request on
the wire.

This is the /auto variant (which does retry after elevating) with the
elevation forbidden. With the flag honoured the read fails once with
0x05; without it the client retries and the test aborts on the
unexpected Read Request, guarding the fix against regression.

Assisted-by: Claude:Opus-4.8
AI disclosure: this change was developed with the assistance of an AI
model (Claude Opus 4.8). The author reviewed every line. The test was
run against the built tree: it passes with patch 1 applied and was
confirmed to fail (client retries, harness aborts) without it.


Compare: https://github.com/bluez/bluez/compare/45fc1030b964%5E...4df3db7680e9

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

                 reply	other threads:[~2026-07-18 20:25 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bluez/bluez/push/refs/heads/1130150/000000-4df3db@github.com \
    --to=noreply@github.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.