selftests/hid: add report descriptor fixup tests
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>
Thu, 3 Nov 2022 15:57:52 +0000 (16:57 +0100)
committerJiri Kosina <jkosina@suse.cz>
Tue, 15 Nov 2022 15:28:39 +0000 (16:28 +0100)
Simple report descriptor override in HID: replace part of the report
descriptor from a static definition in the bpf kernel program.

Note that this test should be run last because we disconnect/reconnect
the device, meaning that it changes the overall uhid device.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
tools/testing/selftests/hid/hid_bpf.c
tools/testing/selftests/hid/progs/hid.c

index f77ee7fe4af416415349a4b836417b57d4e71eae..eb329b5d299febf0e8a07b04d99e21fb6248a45b 100644 (file)
@@ -740,6 +740,38 @@ TEST_F(hid_bpf, test_hid_user_raw_request_call)
        ASSERT_EQ(args.data[1], 2);
 }
 
+/*
+ * Attach hid_rdesc_fixup to the given uhid device,
+ * retrieve and open the matching hidraw node,
+ * check that the hidraw report descriptor has been updated.
+ */
+TEST_F(hid_bpf, test_rdesc_fixup)
+{
+       struct hidraw_report_descriptor rpt_desc = {0};
+       const struct test_program progs[] = {
+               { .name = "hid_rdesc_fixup" },
+       };
+       int err, desc_size;
+
+       LOAD_PROGRAMS(progs);
+
+       /* check that hid_rdesc_fixup() was executed */
+       ASSERT_EQ(self->skel->data->callback2_check, 0x21);
+
+       /* read the exposed report descriptor from hidraw */
+       err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);
+       ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESCSIZE: %d", err);
+
+       /* ensure the new size of the rdesc is bigger than the old one */
+       ASSERT_GT(desc_size, sizeof(rdesc));
+
+       rpt_desc.size = desc_size;
+       err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &rpt_desc);
+       ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESC: %d", err);
+
+       ASSERT_EQ(rpt_desc.value[4], 0x42);
+}
+
 static int libbpf_print_fn(enum libbpf_print_level level,
                           const char *format, va_list args)
 {
index 7e35bb8e1abfe7f525754ceb6acc4e0643c41e91..5758366a90e64f1a568618f7c46b1104e4ff14cc 100644 (file)
@@ -88,3 +88,56 @@ int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
 
        return 0;
 }
+
+static const __u8 rdesc[] = {
+       0x05, 0x01,                             /* USAGE_PAGE (Generic Desktop) */
+       0x09, 0x32,                             /* USAGE (Z) */
+       0x95, 0x01,                             /* REPORT_COUNT (1) */
+       0x81, 0x06,                             /* INPUT (Data,Var,Rel) */
+
+       0x06, 0x00, 0xff,                       /* Usage Page (Vendor Defined Page 1) */
+       0x19, 0x01,                             /* USAGE_MINIMUM (1) */
+       0x29, 0x03,                             /* USAGE_MAXIMUM (3) */
+       0x15, 0x00,                             /* LOGICAL_MINIMUM (0) */
+       0x25, 0x01,                             /* LOGICAL_MAXIMUM (1) */
+       0x95, 0x03,                             /* REPORT_COUNT (3) */
+       0x75, 0x01,                             /* REPORT_SIZE (1) */
+       0x91, 0x02,                             /* Output (Data,Var,Abs) */
+       0x95, 0x01,                             /* REPORT_COUNT (1) */
+       0x75, 0x05,                             /* REPORT_SIZE (5) */
+       0x91, 0x01,                             /* Output (Cnst,Var,Abs) */
+
+       0x06, 0x00, 0xff,                       /* Usage Page (Vendor Defined Page 1) */
+       0x19, 0x06,                             /* USAGE_MINIMUM (6) */
+       0x29, 0x08,                             /* USAGE_MAXIMUM (8) */
+       0x15, 0x00,                             /* LOGICAL_MINIMUM (0) */
+       0x25, 0x01,                             /* LOGICAL_MAXIMUM (1) */
+       0x95, 0x03,                             /* REPORT_COUNT (3) */
+       0x75, 0x01,                             /* REPORT_SIZE (1) */
+       0xb1, 0x02,                             /* Feature (Data,Var,Abs) */
+       0x95, 0x01,                             /* REPORT_COUNT (1) */
+       0x75, 0x05,                             /* REPORT_SIZE (5) */
+       0x91, 0x01,                             /* Output (Cnst,Var,Abs) */
+
+       0xc0,                           /* END_COLLECTION */
+       0xc0,                   /* END_COLLECTION */
+};
+
+SEC("?fmod_ret/hid_bpf_rdesc_fixup")
+int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
+{
+       __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */);
+
+       if (!data)
+               return 0; /* EPERM check */
+
+       callback2_check = data[4];
+
+       /* insert rdesc at offset 73 */
+       __builtin_memcpy(&data[73], rdesc, sizeof(rdesc));
+
+       /* Change Usage Vendor globally */
+       data[4] = 0x42;
+
+       return sizeof(rdesc) + 73;
+}