From patchwork Wed Apr 23 14:40:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovico de Nittis X-Patchwork-Id: 883621 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 742B419F13F for ; Wed, 23 Apr 2025 14:41:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419262; cv=none; b=q33rClu1N+F40JcXDnDX5kTvPmRl4as2OnSHtmBSyhIiU2glv5ffH4rJJxsDhEN6KA1yiZhM4zkgxcOqVDK36XN9x6zpYAGJLr3X7LJm6+qF17mIiqplUn4dod0qWxdxVIOQh6pdmjYt3y5PCLwkz9It38a+HTtZEfhgUHfkM2A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419262; c=relaxed/simple; bh=Fi0MPczyk21pAUbypOskIDPslLKmxMIDpsqDKorEJpk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=f0HPkYBHz3WI8/OnYTqPLK8liFt9laLIx9X4vwiFkJhDQWCptgWW7ZFoAq+AVItI2ZQ0Zew/U0zp979rmQ4yohGX+WJRmuew2eCmivDJ+OvSVGKjULXqVNlBslRWowG3S5J8DV47qe8S67KDnbdqZbw6u1d2ycTbAE+LlCX+h94= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=H5YPH6Kc; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="H5YPH6Kc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1745419258; bh=Fi0MPczyk21pAUbypOskIDPslLKmxMIDpsqDKorEJpk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H5YPH6Kc6FaT94BE/YhSTCc26A43AhJz9TeCO3QWIVz703X8hWDSVjlr/9RtBBjZk fvgO5SQSIbdh9k1l2/igFwmT4MJr5h15HQTSANtVOEogCpq2w6awcaw7/tIImql01Q o/p6UHh/7taEL/p2IksoUaEzWMt3zq/dqQYeYMLKeON4tGCR0/tVdYu7Z1XQOHF7NP 4QRMZQNhEgvbKhwpHKjx8juFaMezn0U5nsWTjz5f3FtrenyGqVDEXoYj1JRbZ/KxdV pf/2JXa1K7yBPEMiOTqBXVUzEEfITB6x3K6HDVCcIpWRQf8go2hIfum8Ilzrnu5Tvi u503Ejfk6faFA== Received: from localhost.localdomain (unknown [81.56.51.115]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: denittis) by bali.collaboradmins.com (Postfix) with ESMTPSA id 7A0CF17E159E; Wed, 23 Apr 2025 16:40:58 +0200 (CEST) From: Ludovico de Nittis To: linux-bluetooth@vger.kernel.org Cc: Ludovico de Nittis Subject: [PATCH BlueZ v2 1/8] src: Add new SixaxisCablePairing property Date: Wed, 23 Apr 2025 16:40:13 +0200 Message-ID: <20250423144020.358828-2-ludovico.denittis@collabora.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250423144020.358828-1-ludovico.denittis@collabora.com> References: <20250423144020.358828-1-ludovico.denittis@collabora.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This adds initial support for a new SixaxisCablePairing property. The property can be used to set a device as being a "real" Sixaxis gamepad and then handle it differently when needed. --- doc/org.bluez.Device.rst | 6 ++++++ src/device.c | 44 ++++++++++++++++++++++++++++++++++++++++ src/device.h | 3 +++ 3 files changed, 53 insertions(+) diff --git a/doc/org.bluez.Device.rst b/doc/org.bluez.Device.rst index 13328249b..2d85d0dc2 100644 --- a/doc/org.bluez.Device.rst +++ b/doc/org.bluez.Device.rst @@ -279,6 +279,12 @@ boolean LegacyPairing [readonly] Bluetooth 2.1 (or newer) devices that have disabled Extended Inquiry Response support. +boolean SixaxisCablePairing [readonly] +`````````````````````````````````````` + + Set to true if the device was paired using the Sixaxis USB custom protocol. + If true, the device connection will happen without enforcing encryption. + string Modalias [readonly, optional] ```````````````````````````````````` diff --git a/src/device.c b/src/device.c index b82a905f9..b11b5c8e4 100644 --- a/src/device.c +++ b/src/device.c @@ -239,6 +239,7 @@ struct btd_device { GSList *watches; /* List of disconnect_data */ bool temporary; bool connectable; + bool sixaxis_cable_pairing; unsigned int disconn_timer; unsigned int discov_timer; unsigned int temporary_timer; /* Temporary/disappear timer */ @@ -507,6 +508,9 @@ static gboolean store_device_info_cb(gpointer user_data) g_key_file_set_boolean(key_file, "General", "Blocked", device->blocked); + g_key_file_set_boolean(key_file, "General", "SixaxisCablePairing", + device->sixaxis_cable_pairing); + if (device->wake_override != WAKE_FLAG_DEFAULT) { g_key_file_set_boolean(key_file, "General", "WakeAllowed", device->wake_override == @@ -908,6 +912,11 @@ bool btd_device_is_trusted(struct btd_device *device) return device->trusted; } +bool device_is_sixaxis_cable_pairing(struct btd_device *device) +{ + return device->sixaxis_cable_pairing; +} + static gboolean dev_property_get_address(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { @@ -1153,6 +1162,17 @@ static gboolean dev_property_get_legacy(const GDBusPropertyTable *property, return TRUE; } +static gboolean dev_property_get_sixaxis_cable_pairing(const GDBusPropertyTable *property, + DBusMessageIter *iter, void *data) +{ + struct btd_device *device = data; + dbus_bool_t val = device->sixaxis_cable_pairing; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val); + + return TRUE; +} + static gboolean dev_property_get_rssi(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { @@ -3483,6 +3503,7 @@ static const GDBusPropertyTable device_properties[] = { { "Trusted", "b", dev_property_get_trusted, dev_property_set_trusted }, { "Blocked", "b", dev_property_get_blocked, dev_property_set_blocked }, { "LegacyPairing", "b", dev_property_get_legacy }, + { "SixaxisCablePairing", "b", dev_property_get_sixaxis_cable_pairing }, { "RSSI", "n", dev_property_get_rssi, NULL, dev_property_exists_rssi }, { "Connected", "b", dev_property_get_connected }, { "UUIDs", "as", dev_property_get_uuids }, @@ -4062,6 +4083,9 @@ next: if (blocked) device_block(device, FALSE); + device->sixaxis_cable_pairing = g_key_file_get_boolean(key_file, "General", + "SixaxisCablePairing", NULL); + /* Load device profile list */ uuids = g_key_file_get_string_list(key_file, "General", "Services", NULL, NULL); @@ -4857,6 +4881,9 @@ void device_merge_duplicate(struct btd_device *dev, struct btd_device *dup) dev->trusted = dup->trusted; dev->blocked = dup->blocked; + /* Skip sixaxis_cable_pairing property because it doesn't support LE, so we + * never expect to have a duplicate device in that case */ + for (l = dup->uuids; l; l = g_slist_next(l)) dev->uuids = g_slist_append(dev->uuids, g_strdup(l->data)); @@ -6416,6 +6443,23 @@ void device_set_legacy(struct btd_device *device, bool legacy) DEVICE_INTERFACE, "LegacyPairing"); } +void device_set_sixaxis_cable_pairing(struct btd_device *device, + gboolean sixaxis_cable_pairing) +{ + if (!device) + return; + + if (device->sixaxis_cable_pairing == sixaxis_cable_pairing) + return; + + DBG("setting sixaxis cable pairing %d", sixaxis_cable_pairing); + + device->sixaxis_cable_pairing = sixaxis_cable_pairing; + + g_dbus_emit_property_changed(dbus_conn, device->path, + DEVICE_INTERFACE, "SixaxisCablePairing"); +} + void device_store_svc_chng_ccc(struct btd_device *device, uint8_t bdaddr_type, uint16_t value) { diff --git a/src/device.h b/src/device.h index 2e4a9771d..c0fa6ec3a 100644 --- a/src/device.h +++ b/src/device.h @@ -94,6 +94,7 @@ bool device_is_connectable(struct btd_device *device); bool device_is_paired(struct btd_device *device, uint8_t bdaddr_type); bool device_is_bonded(struct btd_device *device, uint8_t bdaddr_type); bool btd_device_is_trusted(struct btd_device *device); +bool device_is_sixaxis_cable_pairing(struct btd_device *device); void device_set_paired(struct btd_device *dev, uint8_t bdaddr_type); void device_set_unpaired(struct btd_device *dev, uint8_t bdaddr_type); void btd_device_set_temporary(struct btd_device *device, bool temporary); @@ -101,6 +102,8 @@ void btd_device_set_trusted(struct btd_device *device, gboolean trusted); void btd_device_set_connectable(struct btd_device *device, bool connectable); void device_set_bonded(struct btd_device *device, uint8_t bdaddr_type); void device_set_legacy(struct btd_device *device, bool legacy); +void device_set_sixaxis_cable_pairing(struct btd_device *device, + gboolean sixaxis_cable_pairing); void device_set_rssi_with_delta(struct btd_device *device, int8_t rssi, int8_t delta_threshold); void device_set_rssi(struct btd_device *device, int8_t rssi); From patchwork Wed Apr 23 14:40:15 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovico de Nittis X-Patchwork-Id: 883620 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F630143736 for ; Wed, 23 Apr 2025 14:41:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419264; cv=none; b=T0PHzvD7pWIK2UekuJ91ZuU9xISQsVl4a//LiXW+DLz/5gYUJ1F4npE6Os2o+VFzSXXVR1qCvC4kb3JQb+IE8cN0FhYRsx7rkG/FNlbe/UKvbQWUFKzSONJB966d2QEq594ypQPXV+NAM8SCmUt9KL4syDobVk0H7YBSFJUWVgo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419264; c=relaxed/simple; bh=2pe6XjjC0mhZG7nI/GV4gZgYITk5arIObQn1QvX8Yng=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dRCLxHpQ1W1QmDXzaWBZrOnm0TAmsTuRshuUJBJj198K30b9hfNz7apQtfylvBnxgPMym7Whq/k2HdfJ8pSCC/Q69RkH5V+wscwuEUp+ga+XEpseii0vnzpWYBeaflFNHnZov2mO4GNIbGFMzsWNr3dknEMr0PPFhPj6Z5HHHEA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=KdIk1789; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="KdIk1789" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1745419259; bh=2pe6XjjC0mhZG7nI/GV4gZgYITk5arIObQn1QvX8Yng=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KdIk1789b5qQvXs1Wge2b7G1ATneXCh3G/v5UIOAO4CudrRmLEmqW5Jc7Tk3QD5Mq 45Sfgthml952CtrN575xIGaVhcCtYgsninKn9TUAmQHHTCJZcjEpsxbuYFymfgf+HC 0pqDcCepFdQZTBf4FG6+5JOsnn6JGLIsCwFSVScgp2F4ej3sP//e8cba1djSd1Dj99 wENgLVeORCZ1z39iyE+Hkf5AQDSW1JeD8E0AakldRU3xcEBAsURzHV3EAkbFEAeUwg CEm3L29a5xJt5Bjvj8LDLUWbZj+/VCQ1RHHsQXkvi1R00D+Q5ODzpu1+YRxOI/2+W2 eJ/nRTWzMhBUw== Received: from localhost.localdomain (unknown [81.56.51.115]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: denittis) by bali.collaboradmins.com (Postfix) with ESMTPSA id 2C76817E3613; Wed, 23 Apr 2025 16:40:59 +0200 (CEST) From: Ludovico de Nittis To: linux-bluetooth@vger.kernel.org Cc: Ludovico de Nittis Subject: [PATCH BlueZ v2 3/8] plugins: Set SixaxisCablePairing property when pairing a sixaxis with USB Date: Wed, 23 Apr 2025 16:40:15 +0200 Message-ID: <20250423144020.358828-4-ludovico.denittis@collabora.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250423144020.358828-1-ludovico.denittis@collabora.com> References: <20250423144020.358828-1-ludovico.denittis@collabora.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 If we are pairing a Sixaxis device using a USB cable, we set the SixaxisCablePairing property to flag that event. --- plugins/sixaxis.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/sixaxis.c b/plugins/sixaxis.c index 3e69f1dd2..84dd3891b 100644 --- a/plugins/sixaxis.c +++ b/plugins/sixaxis.c @@ -296,10 +296,13 @@ static void agent_auth_cb(DBusError *derr, void *user_data) remove_device = false; btd_device_set_temporary(closure->device, false); - if (closure->type == CABLE_PAIRING_SIXAXIS) + if (closure->type == CABLE_PAIRING_SIXAXIS) { btd_device_set_record(closure->device, HID_UUID, SIXAXIS_HID_SDP_RECORD); + device_set_sixaxis_cable_pairing(closure->device, true); + } + ba2str(&closure->bdaddr, device_addr); ba2str(¢ral_bdaddr, central_addr); ba2str(adapter_bdaddr, adapter_addr); From patchwork Wed Apr 23 14:40:17 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovico de Nittis X-Patchwork-Id: 883619 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 003E227F756 for ; Wed, 23 Apr 2025 14:41:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419266; cv=none; b=plcnsmzuczuCvpJu4EBCYql0JmtCHoWa07pxw1GJnnXQyN4yoHTHAY3su37SBEfMe7jpMEgB8RFcP4VLoCfE6w2NxZxBxvJfAHqtl3OZkNOzzOh3iojH5+RCveNdonoVJA75VMOniQu6PeTiiF8im7f52MypLjShBWdY06mc0yc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419266; c=relaxed/simple; bh=0DjCJI98QzMAhAv3frqYwLSBbVPpBfRCdeUvHENxUIY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OfY99ofqRi8c8LxhSlorMtvJlFhG5bACD5agCctxbut1/nXkBoAt4u7XjGm9m2qkuNdInQ0K1j5bLI1bDG0Tlw2u9J6K6HyHP4DXhgwnd8ql9Xf1vUmlAMfj6bbUWpXmtZXVakyfJJ2YbpV38v/c8fW3BjmJeYYUHT18Ei4id7M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=l8fw0K8B; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="l8fw0K8B" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1745419260; bh=0DjCJI98QzMAhAv3frqYwLSBbVPpBfRCdeUvHENxUIY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=l8fw0K8B8E5e7kuGIrxf/+lFPJGdjXtq7XjU4GV3KpdXyakLtZ5XfA8XDiyViQ8NH lJL1G+t2DmwkRn8UJvMYlwilepUQo1kH+KfjUpa1FJxG8ZpQqhCDB1TPj+YO+s4Lqm 5h09mpQndi8nDqbMP8X4r2VJWdaaMaPJx7ZmNvEZyD7cS28p0L28r5dmIRI6DWjoss CRC/IFikA1lCYfLFZYkbxdGTDs7L1cFfbmb9IYenKOaSqwSBqWs99TeFxpk3ACo2QD m9F3oEeRV3GB09gBl1MROIMT+MjDkPckuyQ3ton5PdnCF8Sc2Kyp03jHlt9tnq9XTO mZ978VMYAbyqQ== Received: from localhost.localdomain (unknown [81.56.51.115]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: denittis) by bali.collaboradmins.com (Postfix) with ESMTPSA id D088517E3626; Wed, 23 Apr 2025 16:40:59 +0200 (CEST) From: Ludovico de Nittis To: linux-bluetooth@vger.kernel.org Cc: Ludovico de Nittis Subject: [PATCH BlueZ v2 5/8] input: Automatically use security level low when using a sixaxis device Date: Wed, 23 Apr 2025 16:40:17 +0200 Message-ID: <20250423144020.358828-6-ludovico.denittis@collabora.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250423144020.358828-1-ludovico.denittis@collabora.com> References: <20250423144020.358828-1-ludovico.denittis@collabora.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 BT_IO_SEC_LOW is the only way to allow Sixaxis devices to establish a connection. This adds the ability to start the listening input server with BT_IO_SEC_LOW to avoid breaking the Sixaxis support, and then, in `hidp_add_connection()`, we check if either `classic_bonded_only` was disabled or if this device is a Sixaxis. If neither are true, we bump the security back to BT_IO_SEC_MEDIUM, i.e. enforcing encryption. This allows supporting the Sixaxis gamepad without having to change the classic bonded only option. This doesn't cover the case where a sixaxis device gets loaded from storage, or when we are attempting to connect a new sixaxis. Both cases will be handled with followup commits. --- profiles/input/device.c | 6 ++-- profiles/input/manager.c | 3 +- profiles/input/server.c | 62 ++++++++++++++++++++++++++++++++++++++-- profiles/input/server.h | 3 +- 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/profiles/input/device.c b/profiles/input/device.c index 3627573e7..9f05757a6 100644 --- a/profiles/input/device.c +++ b/profiles/input/device.c @@ -1088,8 +1088,10 @@ static int hidp_add_connection(struct input_device *idev) if (device_name_known(idev->device)) device_get_name(idev->device, req->name, sizeof(req->name)); + sixaxis_cable_pairing = device_is_sixaxis_cable_pairing(idev->device); + /* Make sure the device is bonded if required */ - if (classic_bonded_only && !input_device_bonded(idev)) { + if (!sixaxis_cable_pairing && classic_bonded_only && !input_device_bonded(idev)) { error("Rejected connection from !bonded device %s", idev->path); goto cleanup; } @@ -1098,7 +1100,7 @@ static int hidp_add_connection(struct input_device *idev) /* Some platforms may choose to require encryption for all devices */ /* Note that this only matters for pre 2.1 devices as otherwise the */ /* device is encrypted by default by the lower layers */ - if (classic_bonded_only || idev->type == BT_UHID_KEYBOARD) { + if (!sixaxis_cable_pairing && (classic_bonded_only || idev->type == BT_UHID_KEYBOARD)) { if (!bt_io_set(idev->intr_io, &gerr, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID)) { diff --git a/profiles/input/manager.c b/profiles/input/manager.c index d1accc24f..0a1d5c197 100644 --- a/profiles/input/manager.c +++ b/profiles/input/manager.c @@ -33,7 +33,8 @@ static int hid_server_probe(struct btd_profile *p, struct btd_adapter *adapter) { - return server_start(btd_adapter_get_address(adapter)); + return server_start(btd_adapter_get_address(adapter), + btd_adapter_has_sixaxis_cable_pairing(adapter)); } static void hid_server_remove(struct btd_profile *p, diff --git a/profiles/input/server.c b/profiles/input/server.c index 79cf08a66..b4ea5daa9 100644 --- a/profiles/input/server.c +++ b/profiles/input/server.c @@ -266,12 +266,22 @@ drop: g_io_channel_shutdown(chan, TRUE, NULL); } -int server_start(const bdaddr_t *src) +static BtIOSecLevel get_necessary_sec_level(bool device_sixaxis_cable_pairing) +{ + /* Use lower security to allow the Sixaxis gamepad to connect. */ + /* Unless classic bonded only mode is disabled, the security level */ + /* will be bumped again for non sixaxis devices in hidp_add_connection() */ + if (device_sixaxis_cable_pairing) + return BT_IO_SEC_LOW; + + return input_get_classic_bonded_only() ? BT_IO_SEC_MEDIUM : BT_IO_SEC_LOW; +} + +int server_start(const bdaddr_t *src, bool device_sixaxis_cable_pairing) { struct input_server *server; GError *err = NULL; - BtIOSecLevel sec_level = input_get_classic_bonded_only() ? - BT_IO_SEC_MEDIUM : BT_IO_SEC_LOW; + const BtIOSecLevel sec_level = get_necessary_sec_level(device_sixaxis_cable_pairing); server = g_new0(struct input_server, 1); bacpy(&server->src, src); @@ -308,6 +318,52 @@ int server_start(const bdaddr_t *src) return 0; } +int server_set_sixaxis_cable_pairing(const bdaddr_t *src, bool device_sixaxis_cable_pairing) +{ + struct input_server *server; + GSList *l; + BtIOSecLevel sec_level; + const BtIOSecLevel new_sec_level = get_necessary_sec_level(device_sixaxis_cable_pairing); + GError *err = NULL; + + l = g_slist_find_custom(servers, src, server_cmp); + if (!l) + return -1; + + server = l->data; + + bt_io_get(server->ctrl, &err, BT_IO_OPT_SEC_LEVEL, &sec_level, + BT_IO_OPT_INVALID); + if (err) { + error("%s", err->message); + g_error_free(err); + return -1; + } + + if (sec_level == new_sec_level) { + DBG("The listening input server is already using the expected security level"); + return -1; + } + + DBG("Applying the new security level to the listening input server"); + + if (!bt_io_set(server->ctrl, &err, BT_IO_OPT_SEC_LEVEL, new_sec_level, + BT_IO_OPT_INVALID)) { + error("bt_io_set(OPT_SEC_LEVEL): %s", err->message); + g_error_free(err); + return -1; + } + + if (!bt_io_set(server->intr, &err, BT_IO_OPT_SEC_LEVEL, new_sec_level, + BT_IO_OPT_INVALID)) { + error("bt_io_set(OPT_SEC_LEVEL): %s", err->message); + g_error_free(err); + return -1; + } + + return 0; +} + void server_stop(const bdaddr_t *src) { struct input_server *server; diff --git a/profiles/input/server.h b/profiles/input/server.h index 50f4b6135..c8a1b7095 100644 --- a/profiles/input/server.h +++ b/profiles/input/server.h @@ -8,5 +8,6 @@ * */ -int server_start(const bdaddr_t *src); +int server_start(const bdaddr_t *src, bool device_sixaxis_cable_pairing); +int server_set_sixaxis_cable_pairing(const bdaddr_t *src, bool device_sixaxis_cable_pairing); void server_stop(const bdaddr_t *src); From patchwork Wed Apr 23 14:40:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovico de Nittis X-Patchwork-Id: 883618 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6913327F75E for ; Wed, 23 Apr 2025 14:41:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419266; cv=none; b=j0JrMUiLLD1/lJEu1zP8ApmVcygIIgZleHgU1BwYFrDerVHKgvVmxZAE8+bFJcvMGtp7yuq/5Uw5CTKTiWEkKHS8B4tbhYMPLAgttBxeSRH9xTpae6k+F/Vpy/RxcAeJf+pJfmwF1OnnwnsFo/Q0Gjbio+w6xFHhU1431JxbsM4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745419266; c=relaxed/simple; bh=KRMvqAGraYxp/JfLc0lzaBUL/5SN7siwJb6c/xxtkzw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JZ3D1XlbkvxqMkHDBsdHihxmBbelxMVDYGsb63lzFtL6rl+7EW2KoArglL/n9omFC7dbkmZnELDr0zbwtg4xqL4Fl4FndRZDZbqAmsTQ6jKja5XYObMZFowkGDprZ6HJd+owoI7PEtltlsVqRl7uh1VVdhrf5Qz9pFZZw7fW+lk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=MIqnlu+c; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="MIqnlu+c" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1745419261; bh=KRMvqAGraYxp/JfLc0lzaBUL/5SN7siwJb6c/xxtkzw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MIqnlu+cb///TL1QzbVamAWawqk+f/9Ynl2T3R/VkirGgHqcV6xCAaM+fLqa9VOO+ +1OCJj2CTvzue7Y0Salu445bq/q8ozO5W2zvilZmxoeCoJRmIbeT39rHSqcNDy2Otd SMaOt3XQ49Z0By5RvGTDl7fsDkYGtgdHzGGmSCfXP8qrkpImmwf1xNL1vl977MCqwx rCZpftCCOT6mAKCuR0UbPy6VJRkzG8+9GCkkC2qBW+PEyYQngMP9KijyU/75jMEY7V fIVG9ityVU4lYVz4TItIXOitoDAGM22WvsJD6n7Jbd9hVVzXLJxSepCvHIIsB7xQOW 2lbW1i/5ra2rw== Received: from localhost.localdomain (unknown [81.56.51.115]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: denittis) by bali.collaboradmins.com (Postfix) with ESMTPSA id D0B7F17E36BD; Wed, 23 Apr 2025 16:41:00 +0200 (CEST) From: Ludovico de Nittis To: linux-bluetooth@vger.kernel.org Cc: Ludovico de Nittis Subject: [PATCH BlueZ v2 8/8] input: Validate the Sixaxis HID report descriptor Date: Wed, 23 Apr 2025 16:40:20 +0200 Message-ID: <20250423144020.358828-9-ludovico.denittis@collabora.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250423144020.358828-1-ludovico.denittis@collabora.com> References: <20250423144020.358828-1-ludovico.denittis@collabora.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Given that the Sixaxis devices can't work with encryption, i.e. they only work with BT_IO_SEC_LOW, this makes it harder to notice if the device we are talking to is the expected Sixaxis gamepad or an impostor. To reduce the possible attack surface, we ensure that the report descriptor that the device provided resembles what a real Sixaxis gamepad should have. E.g. it should only have Usages for `Joystick`, `Pointer` etc... and nothing unexpected like `Keyboard`. --- profiles/input/device.c | 71 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/profiles/input/device.c b/profiles/input/device.c index 9f05757a6..6f538759b 100644 --- a/profiles/input/device.c +++ b/profiles/input/device.c @@ -1062,9 +1062,72 @@ static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition, return FALSE; } +static bool validate_sixaxis_rd_data(const uint8_t *rd_data, uint16_t rd_size) +{ + uint16_t i; + size_t data_size = 0; + + for (i = 0; i < rd_size; i += 1 + data_size) { + uint8_t b = rd_data[i]; + + /* Long items are reserved for future use, HID 1.11 Section 6.2.2.3 */ + if (b == 0xFE) { + DBG("The sixaxis HID report descriptor has an unexpected long item"); + return false; + } + + /* Extract data following the HID 1.11 Section 6.2.2.2 */ + uint8_t bSize = b & 0x03; + uint8_t bType = (b >> 2) & 0x03; + uint8_t bTag = (b >> 4) & 0x0F; + data_size = bSize == 3 ? 4 : bSize; + + if ((i + 1 + data_size) > rd_size) + break; + + const uint8_t *data = &rd_data[i + 1]; + + if (bType == 1 && bTag == 0x0 && data_size >= 1) { + /* Usage Page (Generic Desktop) */ + if (data_size == 1 && data[0] == 0x01) + continue; + + /* Usage Page (Button) */ + if (data_size == 1 && data[0] == 0x09) + continue; + + /* Usage Page (Vendor Defined Page 1) */ + if (data_size == 2 && data[0] == 0x00 && data[1] == 0xFF) + continue; + + DBG("The sixaxis HID report descriptor has an unexpected Usage Page: 0x%02X", data[0]); + return false; + } + + if (bType == 2 && bTag == 0x0 && data_size >= 1) { + /* Usage (Joystick) */ + if (data_size == 1 && data[0] == 0x04) + continue; + + /* Usage (Pointer) */ + if (data_size == 1 && data[0] == 0x01) + continue; + + /* Axis usages, e.g. Usage (X) */ + if (data_size == 1 && data[0] >= 0x30 && data[0] <= 0x35) + continue; + + DBG("The sixaxis HID report descriptor has an unexpected Usage: 0x%02X", data[0]); + return false; + } + } + return true; +} + static int hidp_add_connection(struct input_device *idev) { struct hidp_connadd_req *req; + bool sixaxis_cable_pairing; GError *gerr = NULL; int err; @@ -1090,6 +1153,14 @@ static int hidp_add_connection(struct input_device *idev) sixaxis_cable_pairing = device_is_sixaxis_cable_pairing(idev->device); + /* The Sixaxis devices must use the security level BT_IO_SEC_LOW to work. */ + /* We reduce the attack surface by ensuring that the report descriptor only */ + /* contains the expected Usages that a real Sixaxis gamepad has */ + if (sixaxis_cable_pairing && !validate_sixaxis_rd_data(req->rd_data, req->rd_size)) { + error("The sixaxis HID SDP record has unexpected entries, rejecting the connection to %s", idev->path); + goto cleanup; + } + /* Make sure the device is bonded if required */ if (!sixaxis_cable_pairing && classic_bonded_only && !input_device_bonded(idev)) { error("Rejected connection from !bonded device %s", idev->path);