Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests/hid: add an infinite loop test for hid_bpf_try_input_report

We don't want this call to allow an infinite loop in HID-BPF, so let's
have some tests.

Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-13-cfd60fb6c79f@kernel.org
Acked-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>

+78
+41
tools/testing/selftests/hid/hid_bpf.c
··· 1205 1205 } 1206 1206 1207 1207 /* 1208 + * Call hid_bpf_input_report against the given uhid device, 1209 + * check that the program is not making infinite loops. 1210 + */ 1211 + TEST_F(hid_bpf, test_hid_infinite_loop_input_report_call) 1212 + { 1213 + const struct test_program progs[] = { 1214 + { .name = "hid_test_infinite_loop_input_report" }, 1215 + }; 1216 + __u8 buf[10] = {0}; 1217 + int err; 1218 + 1219 + LOAD_PROGRAMS(progs); 1220 + 1221 + /* emit hid_hw_output_report from hidraw */ 1222 + buf[0] = 1; /* report ID */ 1223 + buf[1] = 2; 1224 + buf[2] = 42; 1225 + 1226 + uhid_send_event(_metadata, self->uhid_fd, buf, 6); 1227 + 1228 + /* read the data from hidraw */ 1229 + memset(buf, 0, sizeof(buf)); 1230 + err = read(self->hidraw_fd, buf, sizeof(buf)); 1231 + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 1232 + ASSERT_EQ(buf[0], 1); 1233 + ASSERT_EQ(buf[1], 3); 1234 + 1235 + /* read the data from hidraw: hid_bpf_try_input_report should work exactly one time */ 1236 + memset(buf, 0, sizeof(buf)); 1237 + err = read(self->hidraw_fd, buf, sizeof(buf)); 1238 + ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 1239 + ASSERT_EQ(buf[0], 1); 1240 + ASSERT_EQ(buf[1], 4); 1241 + 1242 + /* read the data from hidraw: there should be none */ 1243 + memset(buf, 0, sizeof(buf)); 1244 + err = read(self->hidraw_fd, buf, sizeof(buf)); 1245 + ASSERT_EQ(err, -1) TH_LOG("read_hidraw"); 1246 + } 1247 + 1248 + /* 1208 1249 * Attach hid_insert{0,1,2} to the given uhid device, 1209 1250 * retrieve and open the matching hidraw node, 1210 1251 * inject one event in the uhid device,
+37
tools/testing/selftests/hid/progs/hid.c
··· 561 561 struct hid_bpf_ops test_multiply_events = { 562 562 .hid_device_event = (void *)hid_test_multiply_events, 563 563 }; 564 + 565 + SEC("?struct_ops/hid_device_event") 566 + int BPF_PROG(hid_test_infinite_loop_input_report, struct hid_bpf_ctx *hctx, 567 + enum hid_report_type report_type, __u64 source) 568 + { 569 + __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 6 /* size */); 570 + __u8 buf[6]; 571 + 572 + if (!data) 573 + return 0; /* EPERM check */ 574 + 575 + /* 576 + * we have to use an intermediate buffer as hid_bpf_input_report 577 + * will memset data to \0 578 + */ 579 + __builtin_memcpy(buf, data, sizeof(buf)); 580 + 581 + /* always forward the request as-is to the device, hid-bpf should prevent 582 + * infinite loops. 583 + * the return value is ignored so the event is passing to userspace. 584 + */ 585 + 586 + hid_bpf_try_input_report(hctx, report_type, buf, sizeof(buf)); 587 + 588 + /* each time we process the event, we increment by one data[1]: 589 + * after each successful call to hid_bpf_try_input_report, buf 590 + * has been memcopied into data by the kernel. 591 + */ 592 + data[1] += 1; 593 + 594 + return 0; 595 + } 596 + 597 + SEC(".struct_ops.link") 598 + struct hid_bpf_ops test_infinite_loop_input_report = { 599 + .hid_device_event = (void *)hid_test_infinite_loop_input_report, 600 + };