[PATCH BlueZ v3 6/7] device: unify admin allowlist checks for device services
Frédéric Danis <[email protected]>
| Newsgroups | org.kernel.vger.linux-bluetooth |
|---|---|
| Message-ID | <[email protected]> |
Consolidate device-side admin policy handling into one coherent model so
incoming and outgoing A2DP behavior follows the configured allowlist
consistently.
Why:
- The initial profile-aware adapter mapping fixed role-inverted A2DP cases
for some paths, but device-side service gating still used mixed criteria.
- Host-initiated Connect() could evaluate A2DP services with the wrong UUID
perspective, leading to valid flows being blocked (or blocked flows being
considered valid) under partial allowlists.
What changed:
- Use direct UUID allowlist checks for device service eligibility updates.
- Add A2DP role-aware mapping for device policy UUID selection:
- a2dp-sink -> A2DP Source UUID (110a)
- a2dp-source -> A2DP Sink UUID (110b)
- Apply the same policy UUID resolution in:
- btd_device_all_services_allowed()
- btd_device_update_allowed_services()
Result:
- Device-service policy decisions now align with intended local A2DP role
semantics for both remote-initiated and host-initiated connection paths.
- Admin allowlist enforcement remains strict while eliminating the observed
false block during host->remote A2DP connect attempts.
Assisted-by: GPT:GPT-5.3-Codex
---
src/adapter.c | 6 +++---
src/adapter.h | 3 +++
src/device.c | 35 +++++++++++++++++++++++++++++++----
3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 0cc87f649..138c57800 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -5403,7 +5403,7 @@ static const char *profile_allowlist_uuid(const struct btd_profile *profile)
return NULL;
}
-static bool adapter_profile_is_allowed(struct btd_adapter *adapter,
+bool btd_adapter_is_profile_allowed(struct btd_adapter *adapter,
const struct btd_profile *profile)
{
const char *uuid = profile_allowlist_uuid(profile);
@@ -5422,7 +5422,7 @@ static void probe_profile(struct btd_profile *profile, void *data)
if (profile->adapter_probe == NULL)
return;
- if (!adapter_profile_is_allowed(adapter, profile)) {
+ if (!btd_adapter_is_profile_allowed(adapter, profile)) {
DBG("%s blocked by admin allowlist", profile->name);
return;
}
@@ -5447,7 +5447,7 @@ static void reapply_profile(struct btd_profile *profile, void *data)
active = g_slist_find(adapter->profiles, profile) != NULL;
- if (adapter_profile_is_allowed(adapter, profile)) {
+ if (btd_adapter_is_profile_allowed(adapter, profile)) {
if (!active)
probe_profile(profile, adapter);
return;
diff --git a/src/adapter.h b/src/adapter.h
index a1c887c45..583168f4b 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -27,6 +27,7 @@
struct btd_adapter;
struct btd_device;
+struct btd_profile;
struct queue;
struct btd_adapter *btd_adapter_get_default(void);
@@ -299,6 +300,8 @@ bool btd_adapter_set_allowed_uuids(struct btd_adapter *adapter,
struct queue *uuids);
bool btd_adapter_is_uuid_allowed(struct btd_adapter *adapter,
const char *uuid_str);
+bool btd_adapter_is_profile_allowed(struct btd_adapter *adapter,
+ const struct btd_profile *profile);
void btd_adapter_reapply_allowed_uuids(struct btd_adapter *adapter);
void btd_adapter_load_conn_param(struct btd_adapter *adapter,
diff --git a/src/device.c b/src/device.c
index 65d84be56..c396372be 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2547,21 +2547,44 @@ 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;
struct btd_adapter *adapter = dev->adapter;
struct btd_service *service;
struct btd_profile *profile;
+ const char *uuid;
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);
- if (!profile || !profile->auto_connect)
+ if (!profile || !profile->auto_connect || !uuid)
continue;
- if (!btd_adapter_is_uuid_allowed(adapter, profile->remote_uuid))
+ if (!btd_adapter_is_uuid_allowed(adapter, uuid))
return false;
}
@@ -2575,6 +2598,7 @@ void btd_device_update_allowed_services(struct btd_device *dev)
struct btd_profile *profile;
GSList *l;
bool is_allowed;
+ const char *uuid;
char addr[18];
/* If service discovery is ongoing, let the service discovery complete
@@ -2590,9 +2614,12 @@ 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);
+
+ if (!profile || !uuid)
+ continue;
- is_allowed = btd_adapter_is_uuid_allowed(adapter,
- profile->remote_uuid);
+ is_allowed = btd_adapter_is_uuid_allowed(adapter, uuid);
btd_service_set_allowed(service, is_allowed);
}
}
--
2.43.0