All of lore.kernel.org
 help / color / mirror / Atom feed
From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v2 3/3] test: Cover A2DP disconnection during SetConfiguration
Date: Wed,  7 Oct 2026 15:52:06 -0400	[thread overview]
Message-ID: <20261007195206.350586-3-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20261007195206.350586-1-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Add test_a2dp_disconnect_during_setconf, where the source disconnects
while the sink endpoint has not replied to SetConfiguration yet, and
the late reply, either accepting or rejecting, must be ignored and the
stream configured again on reconnection.

Assisted-by: Claude:claude-opus-5-5
---
 doc/functional-a2dp.rst      | 37 +++++++++++++++++++++++
 test/functional/test_a2dp.py | 58 ++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/doc/functional-a2dp.rst b/doc/functional-a2dp.rst
index 03b18a7201c2..f38a458bb7c2 100644
--- a/doc/functional-a2dp.rst
+++ b/doc/functional-a2dp.rst
@@ -97,3 +97,40 @@ test_a2dp_transport_acquire
 
 :Notes: Acquiring on the source side starts the stream, so the
 	peripheral does not have to acquire its own transport.
+
+test_a2dp_disconnect_during_setconf[accept|reject]
+--------------------------------------------------
+
+:Setup: As above, except the peripheral registers its A2DP Sink
+	endpoint manually with ``Auto Accept: no``, so that `bluetoothd`
+	is left waiting for the reply to
+	``org.bluez.MediaEndpoint1.SetConfiguration``.
+
+:Steps:
+	1. Pair and trust as above.
+	2. Central: ``connect <peripheral bdaddr>``.
+	3. Peripheral: wait for the ``Accept (yes/no):`` prompt, without
+	   answering it.
+	4. Central: ``disconnect <peripheral bdaddr>``.
+	5. Peripheral: answer the pending prompt with ``yes``
+	   (``accept``) or ``no`` (``reject``).
+	6. Central: ``connect <peripheral bdaddr>`` again, and the
+	   peripheral answers ``yes`` to the new prompt.
+
+:Expected:
+	1. ``Pairing successful`` and ``trust succeeded`` on both hosts.
+	2. The peripheral receives ``Endpoint: SetConfiguration``.
+	3. The prompt is shown.
+	4. ``Disconnection successful`` on the central, and the transport
+	   created on the peripheral for the pending configuration is
+	   removed (``[DEL] Transport``).
+	5. The late reply is ignored.
+	6. ``Connection successful``, and a transport appears on both
+	   hosts.
+
+:Notes: Regression test for a crash of `bluetoothd` on the peripheral:
+	the setup of the pending configuration outlived the AVDTP session
+	and the late reply dereferenced a NULL session in
+	``auto_config()``. A late ``yes`` used to also leave the stale
+	transport registered, failing the next connection with
+	``Resource temporarily unavailable``.
diff --git a/test/functional/test_a2dp.py b/test/functional/test_a2dp.py
index 1ab712cd0da1..12348ea05ae2 100644
--- a/test/functional/test_a2dp.py
+++ b/test/functional/test_a2dp.py
@@ -142,3 +142,61 @@ def test_a2dp_transport_acquire(a2dp_hosts):
     source.expect(r"Acquire successful: fd \d+ MTU \d+:\d+")
 
     source.expect(f"Transport {transport} State: active")
+
+
+def start_bluetoothctl_manual_sink(host):
+    """
+    Start bluetoothctl registering an A2DP Sink endpoint that does not
+    auto accept, so that SetConfiguration is left pending until the
+    Accept prompt is answered.
+    """
+    exe = find_exe("client", "bluetoothctl")
+    ctl = host.pexpect.spawn([exe])
+
+    ctl.send("power on\n")
+    ctl.expect("Changing power on succeeded")
+
+    ctl.send(f"endpoint.register {A2DP_SINK_UUID} 0x00\n")
+    ctl.expect(r"Auto Accept \(yes/no\):")
+    ctl.send("no\n")
+    ctl.expect(r"Max Transports \(auto/value\):")
+    ctl.send("a\n")
+    ctl.expect("Endpoint /local/endpoint/ep0 registered")
+    return ctl
+
+
+@pytest.mark.parametrize("reply", ["accept", "reject"])
+@a2dp_host_config
+def test_a2dp_disconnect_during_setconf(hosts, reply):
+    host0, host1 = hosts
+
+    source = start_bluetoothctl(host0, "a2dp-source-sbc.bt")
+    sink = start_bluetoothctl_manual_sink(host1)
+
+    pair(host0, source, host1, sink)
+
+    # Leave SetConfiguration pending on the sink
+    source.send(f"connect {host1.bdaddr}\n")
+    sink.expect("Endpoint: SetConfiguration")
+    _, m = sink.expect(TRANSPORT_RE)
+    transport = m[0].decode("utf-8")
+    sink.expect(r"Accept \(yes/no\):")
+
+    source.send(f"disconnect {host1.bdaddr}\n")
+    source.expect("Disconnection successful")
+
+    # The pending configuration is cleared on disconnection
+    # [DEL] is colored, so match around the escape sequences
+    sink.expect(rf"DEL\S*\] Transport {transport}")
+
+    # Late reply must be ignored
+    sink.send("yes\n" if reply == "accept" else "no\n")
+
+    # bluetoothd is still alive and the stream can be configured again
+    source.send(f"connect {host1.bdaddr}\n")
+    sink.expect("Endpoint: SetConfiguration")
+    sink.expect(TRANSPORT_RE)
+    sink.expect(r"Accept \(yes/no\):")
+    sink.send("yes\n")
+    source.expect("Connection successful")
+    source.expect(TRANSPORT_RE)
-- 
2.55.0


  parent reply	other threads:[~2026-10-07 19:52 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-07 19:52 [PATCH BlueZ v2 1/3] a2dp: Fix UAF after rejected SetConfiguration Luiz Augusto von Dentz
2026-10-07 19:52 ` [PATCH BlueZ v2 2/3] a2dp: Fix crash on NULL session in auto_config Luiz Augusto von Dentz
2026-10-07 19:52 ` Luiz Augusto von Dentz [this message]
2026-10-08  0:07 ` [BlueZ,v2,1/3] a2dp: Fix UAF after rejected SetConfiguration bluez.test.bot
2026-10-08 15:00 ` [PATCH BlueZ v2 1/3] " patchwork-bot+bluetooth

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=20261007195206.350586-3-luiz.dentz@gmail.com \
    --to=luiz.dentz@gmail.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.