Thread (6 messages) 6 messages, 3 authors, 26d ago

[PATCH BlueZ v1 2/4] adapter: Unify the A2DP admin allowlist UUID mapping

flat view
COLD26d

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2026-09-10 18:42:30
Subsystem: the rest · Maintainer: Linus Torvalds

From: Luiz Augusto von Dentz <redacted>

The allowlist enforcement added across the adapter, device and A2DP
layers ended up using three different UUIDs for the same two profiles:
adapter.c mapped both a2dp-source and a2dp-sink to ADVANCED_AUDIO_UUID
(0x110d), while device.c and a2dp.c mapped them to the local role UUIDs
0x110a and 0x110b. An allowlist containing only 0x110a therefore blocked
the a2dp-sink adapter probe outright, so the finer grained SEP checks in
a2dp.c never ran.

Add btd_profile_get_policy_uuid() as the single place resolving a
profile to the UUID of the local service it provides. btd_profile names
and remote_uuid describe the remote role, so the A2DP profiles are
inverted there: "a2dp-source" registers the local Sink server and
"a2dp-sink" registers the local Source server. This matches what
device.c and a2dp.c already do.

Note that allowlisting 0x110d alone no longer enables A2DP; the local
role UUIDs 0x110a and/or 0x110b have to be listed.

This also drops the hardcoded profile name table in adapter.c. Every
entry but the two A2DP ones just returned profile->remote_uuid, and any
profile without a local_uuid that was missing from the table resolved to
NULL, i.e. was allowed unconditionally regardless of the allowlist.

Assisted-by: opencode:claude-opus-5
---
 src/adapter.c | 49 +------------------------------------------------
 src/device.c  | 25 ++-----------------------
 src/profile.c | 24 ++++++++++++++++++++++++
 src/profile.h |  7 +++++++
 4 files changed, 34 insertions(+), 71 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 157d7392d32c..fc734424be07 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -5353,59 +5353,12 @@ static void load_drivers(struct btd_adapter *adapter)
 		probe_driver(adapter, l->data);
 }
 
-struct profile_allowlist_map {
-	const char *name;
-	const char *uuid;
-	bool use_remote_uuid;
-};
-
-/*
- * Adapter server policy UUID defaults to local_uuid when available.
- * Profiles listed below are exceptions.
- *
- * A2DP profiles map to ADVANCED_AUDIO_UUID so profile probe gating matches
- * the A2DP profile class (0x110d), while adapter service registration/removal
- * still filters specific Source/Sink records by their own UUIDs.
- */
-static const struct profile_allowlist_map profile_allowlist_map[] = {
-	{ "a2dp-source", ADVANCED_AUDIO_UUID, false },
-	{ "a2dp-sink", ADVANCED_AUDIO_UUID, false },
-	{ "audio-avrcp-target", NULL, true },
-	{ "avrcp-controller", NULL, true },
-	{ "vcp", NULL, true },
-	{ "micp", NULL, true },
-	{ "ccp", NULL, true },
-	{ "gmap", NULL, true },
-	{ "tmap", NULL, true },
-	{ "bass", NULL, true },
-	{ "bap", NULL, true },
-	{ "mcp-gmcs", NULL, true },
-};
-
 static const char *profile_allowlist_uuid(const struct btd_profile *profile)
 {
-	size_t i;
-
 	if (profile->local_uuid)
 		return profile->local_uuid;
 
-	if (!profile->name)
-		return NULL;
-
-	for (i = 0; i < ARRAY_SIZE(profile_allowlist_map); i++) {
-		const struct profile_allowlist_map *entry =
-						&profile_allowlist_map[i];
-
-		if (strcmp(profile->name, entry->name))
-			continue;
-
-		if (entry->use_remote_uuid)
-			return profile->remote_uuid;
-
-		return entry->uuid;
-	}
-
-	return NULL;
+	return btd_profile_get_policy_uuid(profile);
 }
 
 bool btd_adapter_is_profile_allowed(struct btd_adapter *adapter,
diff --git a/src/device.c b/src/device.c
index 8da576ec5932..ec74c44ac4aa 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2547,27 +2547,6 @@ static struct btd_service *find_connectable_service(struct btd_device *dev,
 	return NULL;
 }
 
-static const char *service_policy_uuid(const struct btd_profile *profile)
-{
-	if (!profile)
-		return NULL;
-
-	/*
-	 * For A2DP device services, apply admin policy by local role UUID:
-	 * - a2dp-sink profile is local source role  (110a)
-	 * - a2dp-source profile is local sink role  (110b)
-	 */
-	if (profile->name) {
-		if (!strcmp(profile->name, "a2dp-sink"))
-			return A2DP_SOURCE_UUID;
-
-		if (!strcmp(profile->name, "a2dp-source"))
-			return A2DP_SINK_UUID;
-	}
-
-	return profile->remote_uuid;
-}
-
 bool btd_device_all_services_allowed(struct btd_device *dev)
 {
 	GSList *l;
@@ -2579,7 +2558,7 @@ bool btd_device_all_services_allowed(struct btd_device *dev)
 	for (l = dev->services; l != NULL; l = g_slist_next(l)) {
 		service = l->data;
 		profile = btd_service_get_profile(service);
-		uuid = service_policy_uuid(profile);
+		uuid = btd_profile_get_policy_uuid(profile);
 
 		if (!profile || !profile->auto_connect || !uuid)
 			continue;
@@ -2614,7 +2593,7 @@ void btd_device_update_allowed_services(struct btd_device *dev)
 	for (l = dev->services; l != NULL; l = g_slist_next(l)) {
 		service = l->data;
 		profile = btd_service_get_profile(service);
-		uuid = service_policy_uuid(profile);
+		uuid = btd_profile_get_policy_uuid(profile);
 
 		if (!profile || !uuid)
 			continue;
diff --git a/src/profile.c b/src/profile.c
index 97fffe9b4d5c..e5b1cdfc5d33 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -16,6 +16,7 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 
 #include <glib.h>
@@ -753,6 +754,29 @@ void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
 	}
 }
 
+const char *btd_profile_get_policy_uuid(const struct btd_profile *profile)
+{
+	if (!profile)
+		return NULL;
+
+	/*
+	 * The admin allowlist is expressed in terms of the services the local
+	 * adapter exposes, while btd_profile names and remote_uuid describe
+	 * the remote role. The A2DP profiles therefore have to be inverted:
+	 * the "a2dp-source" profile drives the local Sink server and the
+	 * "a2dp-sink" profile drives the local Source server.
+	 */
+	if (profile->name) {
+		if (!strcmp(profile->name, "a2dp-source"))
+			return A2DP_SINK_UUID;
+
+		if (!strcmp(profile->name, "a2dp-sink"))
+			return A2DP_SOURCE_UUID;
+	}
+
+	return profile->remote_uuid;
+}
+
 static struct btd_profile *btd_profile_find_uuid(const char *uuid)
 {
 	GSList *l, *next;
diff --git a/src/profile.h b/src/profile.h
index 04a99528b4be..270f09ea2b96 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -84,6 +84,13 @@ struct btd_profile {
 void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
 								void *data);
 
+/*
+ * Return the UUID of the local service a profile provides, for use by the
+ * admin policy allowlist. Returns NULL when the profile has no service to
+ * match against.
+ */
+const char *btd_profile_get_policy_uuid(const struct btd_profile *profile);
+
 int btd_profile_register(struct btd_profile *profile);
 void btd_profile_unregister(struct btd_profile *profile);
 
-- 
2.55.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help