@@ -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 attach 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 (classic_bonded_only && !sixaxis_cable_pairing && !input_device_bonded(idev)) {
error("Rejected connection from !bonded device %s", idev->path);