1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022-2024 Red Hat */ 3 #include "hid.skel.h" 4 #include "hid_common.h" 5 #include <bpf/bpf.h> 6 7 struct hid_hw_request_syscall_args { 8 __u8 data[MAX_BUF_SIZE]; 9 unsigned int hid; 10 int retval; 11 size_t size; 12 enum hid_report_type type; 13 __u8 request_type; 14 }; 15 16 FIXTURE(hid_bpf) { 17 struct uhid_device hid; 18 int hidraw_fd; 19 struct hid *skel; 20 struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */ 21 }; 22 static void detach_bpf(FIXTURE_DATA(hid_bpf) * self) 23 { 24 int i; 25 26 if (self->hidraw_fd) 27 close(self->hidraw_fd); 28 self->hidraw_fd = 0; 29 30 if (!self->skel) 31 return; 32 33 hid__detach(self->skel); 34 35 for (i = 0; i < ARRAY_SIZE(self->hid_links); i++) { 36 if (self->hid_links[i]) 37 bpf_link__destroy(self->hid_links[i]); 38 } 39 40 hid__destroy(self->skel); 41 self->skel = NULL; 42 } 43 44 FIXTURE_TEARDOWN(hid_bpf) { 45 void *uhid_err; 46 47 uhid_destroy(_metadata, &self->hid); 48 49 detach_bpf(self); 50 pthread_join(self->hid.tid, &uhid_err); 51 } 52 #define TEARDOWN_LOG(fmt, ...) do { \ 53 TH_LOG(fmt, ##__VA_ARGS__); \ 54 hid_bpf_teardown(_metadata, self, variant); \ 55 } while (0) 56 57 FIXTURE_VARIANT(hid_bpf) { 58 __u8 *rdesc; 59 size_t rdesc_size; 60 }; 61 62 FIXTURE_VARIANT_ADD(hid_bpf, numbered) { 63 .rdesc = rdesc, 64 .rdesc_size = sizeof(rdesc), 65 }; 66 67 FIXTURE_VARIANT_ADD(hid_bpf, unnumbered) { 68 .rdesc = fido2_rdesc, 69 .rdesc_size = sizeof(fido2_rdesc), 70 }; 71 72 FIXTURE_SETUP(hid_bpf) 73 { 74 int err; 75 76 err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a36, 77 variant->rdesc, variant->rdesc_size); 78 ASSERT_OK(err); 79 } 80 81 struct test_program { 82 const char *name; 83 int insert_head; 84 }; 85 #define LOAD_PROGRAMS(progs) \ 86 load_programs(progs, ARRAY_SIZE(progs), false, _metadata, self, variant) 87 #define LOAD_PROGRAMS_MAY_FAIL(progs) \ 88 load_programs(progs, ARRAY_SIZE(progs), true, _metadata, self, variant) 89 #define LOAD_BPF \ 90 load_programs(NULL, 0, false, _metadata, self, variant) 91 static int load_programs(const struct test_program programs[], 92 const size_t progs_count, 93 bool load_may_fail, 94 struct __test_metadata *_metadata, 95 FIXTURE_DATA(hid_bpf) * self, 96 const FIXTURE_VARIANT(hid_bpf) * variant) 97 { 98 struct bpf_map *iter_map; 99 int err = -EINVAL; 100 101 ASSERT_LE(progs_count, ARRAY_SIZE(self->hid_links)) 102 TH_LOG("too many programs are to be loaded"); 103 104 /* open the bpf file */ 105 self->skel = hid__open(); 106 ASSERT_OK_PTR(self->skel) TEARDOWN_LOG("Error while calling hid__open"); 107 108 /* 109 * Disable all struct_ops maps by default so libbpf does not autoload 110 * programs referenced by maps that are unrelated to the current test. 111 */ 112 bpf_object__for_each_map(iter_map, *self->skel->skeleton->obj) { 113 if (bpf_map__type(iter_map) == BPF_MAP_TYPE_STRUCT_OPS) { 114 err = bpf_map__set_autocreate(iter_map, false); 115 ASSERT_OK(err) TH_LOG("can not disable struct_ops map '%s'", 116 bpf_map__name(iter_map)); 117 } 118 119 bpf_map__set_autoattach(iter_map, false); 120 } 121 122 for (int i = 0; i < progs_count; i++) { 123 struct bpf_program *prog; 124 struct bpf_map *map; 125 int *ops_hid_id; 126 127 prog = bpf_object__find_program_by_name(*self->skel->skeleton->obj, 128 programs[i].name); 129 ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name); 130 131 bpf_program__set_autoload(prog, true); 132 133 map = bpf_object__find_map_by_name(*self->skel->skeleton->obj, 134 programs[i].name + 4); 135 ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'", 136 programs[i].name + 4); 137 138 err = bpf_map__set_autocreate(map, true); 139 ASSERT_OK(err) TH_LOG("can not enable struct_ops map '%s'", 140 programs[i].name + 4); 141 142 /* hid_id is the first field of struct hid_bpf_ops */ 143 ops_hid_id = bpf_map__initial_value(map, NULL); 144 ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data"); 145 146 *ops_hid_id = self->hid.hid_id; 147 } 148 149 err = hid__load(self->skel); 150 if (err && load_may_fail) 151 return err; 152 153 ASSERT_OK(err) TH_LOG("hid_skel_load failed: %d", err); 154 155 for (int i = 0; i < progs_count; i++) { 156 struct bpf_map *map; 157 158 map = bpf_object__find_map_by_name(*self->skel->skeleton->obj, 159 programs[i].name + 4); 160 ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'", 161 programs[i].name + 4); 162 163 self->hid_links[i] = bpf_map__attach_struct_ops(map); 164 ASSERT_OK_PTR(self->hid_links[i]) TH_LOG("failed to attach struct ops '%s'", 165 programs[i].name + 4); 166 } 167 168 hid__attach(self->skel); 169 170 self->hidraw_fd = open_hidraw(&self->hid); 171 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 172 return 0; 173 } 174 175 /* 176 * A simple test to see if the fixture is working fine. 177 * If this fails, none of the other tests will pass. 178 */ 179 TEST_F(hid_bpf, test_create_uhid) 180 { 181 } 182 183 /* 184 * Attach hid_first_event to the given uhid device, 185 * retrieve and open the matching hidraw node, 186 * inject one event in the uhid device, 187 * check that the program sees it and can change the data 188 */ 189 TEST_F(hid_bpf, raw_event) 190 { 191 const struct test_program progs[] = { 192 { .name = "hid_first_event" }, 193 }; 194 __u8 buf[MAX_BUF_SIZE] = {0}; 195 int err; 196 197 LOAD_PROGRAMS(progs); 198 199 /* check that the program is correctly loaded */ 200 ASSERT_EQ(self->skel->data->callback_check, 52) TH_LOG("callback_check1"); 201 ASSERT_EQ(self->skel->data->callback2_check, 52) TH_LOG("callback2_check1"); 202 203 /* inject one event */ 204 buf[0] = 1; 205 buf[1] = 42; 206 uhid_send_event(_metadata, &self->hid, buf, 6); 207 208 /* check that hid_first_event() was executed */ 209 ASSERT_EQ(self->skel->data->callback_check, 42) TH_LOG("callback_check1"); 210 211 /* read the data from hidraw */ 212 memset(buf, 0, sizeof(buf)); 213 err = read(self->hidraw_fd, buf, sizeof(buf)); 214 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 215 ASSERT_EQ(buf[0], 1); 216 ASSERT_EQ(buf[2], 47); 217 218 /* inject another event */ 219 memset(buf, 0, sizeof(buf)); 220 buf[0] = 1; 221 buf[1] = 47; 222 uhid_send_event(_metadata, &self->hid, buf, 6); 223 224 /* check that hid_first_event() was executed */ 225 ASSERT_EQ(self->skel->data->callback_check, 47) TH_LOG("callback_check1"); 226 227 /* read the data from hidraw */ 228 memset(buf, 0, sizeof(buf)); 229 err = read(self->hidraw_fd, buf, sizeof(buf)); 230 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 231 ASSERT_EQ(buf[2], 52); 232 } 233 234 /* 235 * Attach hid_first_event to the given uhid device, 236 * retrieve and open the matching hidraw node, 237 * inject one event in the uhid device, 238 * check that the program sees it and can change the data 239 */ 240 TEST_F(hid_bpf, subprog_raw_event) 241 { 242 const struct test_program progs[] = { 243 { .name = "hid_subprog_first_event" }, 244 }; 245 __u8 buf[MAX_BUF_SIZE] = {0}; 246 int err; 247 248 LOAD_PROGRAMS(progs); 249 250 /* inject one event */ 251 buf[0] = 1; 252 buf[1] = 42; 253 uhid_send_event(_metadata, &self->hid, buf, 6); 254 255 /* read the data from hidraw */ 256 memset(buf, 0, sizeof(buf)); 257 err = read(self->hidraw_fd, buf, sizeof(buf)); 258 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 259 ASSERT_EQ(buf[0], 1); 260 ASSERT_EQ(buf[2], 47); 261 262 /* inject another event */ 263 memset(buf, 0, sizeof(buf)); 264 buf[0] = 1; 265 buf[1] = 47; 266 uhid_send_event(_metadata, &self->hid, buf, 6); 267 268 /* read the data from hidraw */ 269 memset(buf, 0, sizeof(buf)); 270 err = read(self->hidraw_fd, buf, sizeof(buf)); 271 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 272 ASSERT_EQ(buf[2], 52); 273 } 274 275 /* 276 * Attach hid_first_event to the given uhid device, 277 * attempt at re-attaching it, we should not lock and 278 * return an invalid struct bpf_link 279 */ 280 TEST_F(hid_bpf, multiple_attach) 281 { 282 const struct test_program progs[] = { 283 { .name = "hid_first_event" }, 284 }; 285 struct bpf_link *link; 286 287 LOAD_PROGRAMS(progs); 288 289 link = bpf_map__attach_struct_ops(self->skel->maps.first_event); 290 ASSERT_NULL(link) TH_LOG("unexpected return value when re-attaching the struct_ops"); 291 } 292 293 /* 294 * Ensures that we can attach/detach programs 295 */ 296 TEST_F(hid_bpf, test_attach_detach) 297 { 298 const struct test_program progs[] = { 299 { .name = "hid_first_event" }, 300 { .name = "hid_second_event" }, 301 }; 302 struct bpf_link *link; 303 __u8 buf[MAX_BUF_SIZE] = {0}; 304 int err, link_fd; 305 306 LOAD_PROGRAMS(progs); 307 308 link = self->hid_links[0]; 309 ASSERT_OK_PTR(link) TH_LOG("HID-BPF link not created"); 310 311 link_fd = bpf_link__fd(link); 312 ASSERT_GE(link_fd, 0) TH_LOG("HID-BPF link FD not valid"); 313 314 /* inject one event */ 315 buf[0] = 1; 316 buf[1] = 42; 317 uhid_send_event(_metadata, &self->hid, buf, 6); 318 319 /* read the data from hidraw */ 320 memset(buf, 0, sizeof(buf)); 321 err = read(self->hidraw_fd, buf, sizeof(buf)); 322 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 323 ASSERT_EQ(buf[0], 1); 324 ASSERT_EQ(buf[2], 47); 325 326 /* make sure both programs are run */ 327 ASSERT_EQ(buf[3], 52); 328 329 /* pin the first program and immediately unpin it */ 330 #define PIN_PATH "/sys/fs/bpf/hid_first_event" 331 err = bpf_obj_pin(link_fd, PIN_PATH); 332 ASSERT_OK(err) TH_LOG("error while calling bpf_obj_pin"); 333 remove(PIN_PATH); 334 #undef PIN_PATH 335 usleep(100000); 336 337 /* detach the program */ 338 detach_bpf(self); 339 340 self->hidraw_fd = open_hidraw(&self->hid); 341 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 342 343 /* inject another event */ 344 memset(buf, 0, sizeof(buf)); 345 buf[0] = 1; 346 buf[1] = 47; 347 uhid_send_event(_metadata, &self->hid, buf, 6); 348 349 /* read the data from hidraw */ 350 memset(buf, 0, sizeof(buf)); 351 err = read(self->hidraw_fd, buf, sizeof(buf)); 352 ASSERT_EQ(err, 6) TH_LOG("read_hidraw_no_bpf"); 353 ASSERT_EQ(buf[0], 1); 354 ASSERT_EQ(buf[1], 47); 355 ASSERT_EQ(buf[2], 0); 356 ASSERT_EQ(buf[3], 0); 357 358 /* re-attach our program */ 359 360 LOAD_PROGRAMS(progs); 361 362 /* inject one event */ 363 memset(buf, 0, sizeof(buf)); 364 buf[0] = 1; 365 buf[1] = 42; 366 uhid_send_event(_metadata, &self->hid, buf, 6); 367 368 /* read the data from hidraw */ 369 memset(buf, 0, sizeof(buf)); 370 err = read(self->hidraw_fd, buf, sizeof(buf)); 371 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 372 ASSERT_EQ(buf[0], 1); 373 ASSERT_EQ(buf[2], 47); 374 ASSERT_EQ(buf[3], 52); 375 } 376 377 /* 378 * Attach hid_change_report_id to the given uhid device, 379 * retrieve and open the matching hidraw node, 380 * inject one event in the uhid device, 381 * check that the program sees it and can change the data 382 */ 383 TEST_F(hid_bpf, test_hid_change_report) 384 { 385 const struct test_program progs[] = { 386 { .name = "hid_change_report_id" }, 387 }; 388 __u8 buf[MAX_BUF_SIZE] = {0}; 389 int err; 390 391 LOAD_PROGRAMS(progs); 392 393 /* inject one event */ 394 buf[0] = 1; 395 buf[1] = 42; 396 uhid_send_event(_metadata, &self->hid, buf, 6); 397 398 /* read the data from hidraw */ 399 memset(buf, 0, sizeof(buf)); 400 err = read(self->hidraw_fd, buf, sizeof(buf)); 401 ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); 402 ASSERT_EQ(buf[0], 2); 403 ASSERT_EQ(buf[1], 42); 404 ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test"); 405 } 406 407 /* 408 * Call hid_bpf_input_report against the given uhid device, 409 * check that the program is called and does the expected. 410 */ 411 TEST_F(hid_bpf, test_hid_user_input_report_call) 412 { 413 struct hid_hw_request_syscall_args args = { 414 .retval = -1, 415 .size = MAX_BUF_SIZE, 416 }; 417 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, 418 .ctx_in = &args, 419 .ctx_size_in = sizeof(args), 420 ); 421 __u8 buf[MAX_BUF_SIZE] = {0}; 422 int err, prog_fd; 423 424 LOAD_BPF; 425 426 args.hid = self->hid.hid_id; 427 args.data[0] = 1; /* report ID */ 428 args.data[1] = 2; 429 args.data[2] = 42; 430 431 if (variant->rdesc == fido2_rdesc) 432 args.data[0] = 0; 433 434 prog_fd = bpf_program__fd(self->skel->progs.hid_user_input_report); 435 436 /* check that there is no data to read from hidraw */ 437 memset(buf, 0, sizeof(buf)); 438 err = read(self->hidraw_fd, buf, sizeof(buf)); 439 ASSERT_EQ(err, -1) TH_LOG("read_hidraw"); 440 441 err = bpf_prog_test_run_opts(prog_fd, &tattrs); 442 443 ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts"); 444 445 ASSERT_EQ(args.retval, 0); 446 447 /* read the data from hidraw */ 448 memset(buf, 0, sizeof(buf)); 449 err = read(self->hidraw_fd, buf, sizeof(buf)); 450 if (variant->rdesc == rdesc) { 451 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 452 } else { 453 ASSERT_EQ(err, 64) 454 TH_LOG("read_hidraw"); 455 } 456 ASSERT_EQ(buf[0], args.data[0]); 457 ASSERT_EQ(buf[1], 2); 458 ASSERT_EQ(buf[2], 42); 459 } 460 461 /* 462 * Call hid_bpf_hw_output_report against the given uhid device, 463 * check that the program is called and does the expected. 464 */ 465 TEST_F(hid_bpf, test_hid_user_output_report_call) 466 { 467 struct hid_hw_request_syscall_args args = { 468 .retval = -1, 469 .size = MAX_BUF_SIZE, 470 }; 471 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, 472 .ctx_in = &args, 473 .ctx_size_in = sizeof(args), 474 ); 475 int err, cond_err, prog_fd; 476 struct timespec time_to_wait; 477 478 LOAD_BPF; 479 480 args.hid = self->hid.hid_id; 481 args.data[0] = 1; /* report ID */ 482 args.data[1] = 2; 483 args.data[2] = 42; 484 485 if (variant->rdesc == fido2_rdesc) 486 args.data[0] = 0; 487 488 prog_fd = bpf_program__fd(self->skel->progs.hid_user_output_report); 489 490 pthread_mutex_lock(&uhid_output_mtx); 491 492 memset(output_report, 0, sizeof(output_report)); 493 clock_gettime(CLOCK_REALTIME, &time_to_wait); 494 time_to_wait.tv_sec += 2; 495 496 err = bpf_prog_test_run_opts(prog_fd, &tattrs); 497 cond_err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait); 498 499 ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts"); 500 ASSERT_OK(cond_err) TH_LOG("error while calling waiting for the condition"); 501 502 if (variant->rdesc == rdesc) { 503 ASSERT_EQ(args.retval, 3); 504 } else if (variant->rdesc == fido2_rdesc) { 505 ASSERT_EQ(args.retval, 65) 506 TH_LOG("report size error, should have 64 + 1 extra byte for the report ID 0"); 507 } 508 509 ASSERT_EQ(output_report[0], args.data[0]); 510 ASSERT_EQ(output_report[1], 2); 511 ASSERT_EQ(output_report[2], 42); 512 513 pthread_mutex_unlock(&uhid_output_mtx); 514 } 515 516 /* 517 * Call hid_hw_raw_request against the given uhid device, 518 * check that the program is called and does the expected. 519 */ 520 TEST_F(hid_bpf, test_hid_user_raw_request_call) 521 { 522 struct hid_hw_request_syscall_args args = { 523 .retval = -1, 524 .type = HID_FEATURE_REPORT, 525 .request_type = HID_REQ_GET_REPORT, 526 .size = MAX_BUF_SIZE, 527 }; 528 DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs, 529 .ctx_in = &args, 530 .ctx_size_in = sizeof(args), 531 ); 532 int err, prog_fd; 533 534 LOAD_BPF; 535 536 args.hid = self->hid.hid_id; 537 args.data[0] = 1; /* report ID */ 538 539 prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request); 540 541 err = bpf_prog_test_run_opts(prog_fd, &tattrs); 542 ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts"); 543 544 ASSERT_EQ(args.retval, 2); 545 546 ASSERT_EQ(args.data[1], 2); 547 } 548 549 /* 550 * Call hid_hw_raw_request against the given uhid device, 551 * check that the program is called and prevents the 552 * call to uhid. 553 */ 554 TEST_F(hid_bpf, test_hid_filter_raw_request_call) 555 { 556 const struct test_program progs[] = { 557 { .name = "hid_test_filter_raw_request" }, 558 }; 559 __u8 buf[MAX_BUF_SIZE] = {0}; 560 int err; 561 562 LOAD_PROGRAMS(progs); 563 564 /* first check that we did not attach to device_event */ 565 566 /* inject one event */ 567 buf[0] = 1; 568 buf[1] = 42; 569 uhid_send_event(_metadata, &self->hid, buf, 6); 570 571 /* read the data from hidraw */ 572 memset(buf, 0, sizeof(buf)); 573 err = read(self->hidraw_fd, buf, sizeof(buf)); 574 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 575 ASSERT_EQ(buf[0], 1); 576 ASSERT_EQ(buf[1], 42); 577 ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test"); 578 579 /* now check that our program is preventing hid_hw_raw_request() */ 580 581 /* emit hid_hw_raw_request from hidraw */ 582 /* Get Feature */ 583 memset(buf, 0, sizeof(buf)); 584 buf[0] = 0x1; /* Report Number */ 585 err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); 586 ASSERT_LT(err, 0) TH_LOG("unexpected success while reading HIDIOCGFEATURE: %d", err); 587 ASSERT_EQ(errno, 20) TH_LOG("unexpected error code while reading HIDIOCGFEATURE: %d", 588 errno); 589 590 /* remove our bpf program and check that we can now emit commands */ 591 592 /* detach the program */ 593 detach_bpf(self); 594 595 self->hidraw_fd = open_hidraw(&self->hid); 596 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 597 598 err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); 599 ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGFEATURE: %d", err); 600 } 601 602 /* 603 * Call hid_hw_raw_request against the given uhid device, 604 * check that the program is called and can issue the call 605 * to uhid and transform the answer. 606 */ 607 TEST_F(hid_bpf, test_hid_change_raw_request_call) 608 { 609 const struct test_program progs[] = { 610 { .name = "hid_test_hidraw_raw_request" }, 611 }; 612 __u8 buf[MAX_BUF_SIZE] = {0}; 613 int err; 614 615 LOAD_PROGRAMS(progs); 616 617 /* emit hid_hw_raw_request from hidraw */ 618 /* Get Feature */ 619 memset(buf, 0, sizeof(buf)); 620 buf[0] = 0x1; /* Report Number */ 621 err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); 622 ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err); 623 624 ASSERT_EQ(buf[0], 2); 625 ASSERT_EQ(buf[1], 3); 626 ASSERT_EQ(buf[2], 4); 627 } 628 629 /* 630 * Call hid_hw_raw_request against the given uhid device, 631 * check that the program is not making infinite loops. 632 */ 633 TEST_F(hid_bpf, test_hid_infinite_loop_raw_request_call) 634 { 635 const struct test_program progs[] = { 636 { .name = "hid_test_infinite_loop_raw_request" }, 637 }; 638 __u8 buf[MAX_BUF_SIZE] = {0}; 639 int err; 640 641 LOAD_PROGRAMS(progs); 642 643 /* emit hid_hw_raw_request from hidraw */ 644 /* Get Feature */ 645 memset(buf, 0, sizeof(buf)); 646 buf[0] = 0x1; /* Report Number */ 647 err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf); 648 ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err); 649 } 650 651 /* 652 * Call hid_hw_output_report against the given uhid device, 653 * check that the program is called and prevents the 654 * call to uhid. 655 */ 656 TEST_F(hid_bpf, test_hid_filter_output_report_call) 657 { 658 const struct test_program progs[] = { 659 { .name = "hid_test_filter_output_report" }, 660 }; 661 __u8 buf[MAX_BUF_SIZE] = {0}; 662 int err; 663 664 LOAD_PROGRAMS(progs); 665 666 /* first check that we did not attach to device_event */ 667 668 /* inject one event */ 669 buf[0] = 1; 670 buf[1] = 42; 671 uhid_send_event(_metadata, &self->hid, buf, 6); 672 673 /* read the data from hidraw */ 674 memset(buf, 0, sizeof(buf)); 675 err = read(self->hidraw_fd, buf, sizeof(buf)); 676 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 677 ASSERT_EQ(buf[0], 1); 678 ASSERT_EQ(buf[1], 42); 679 ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test"); 680 681 /* now check that our program is preventing hid_hw_output_report() */ 682 683 buf[0] = 1; /* report ID */ 684 buf[1] = 2; 685 buf[2] = 42; 686 687 err = write(self->hidraw_fd, buf, 3); 688 ASSERT_LT(err, 0) TH_LOG("unexpected success while sending hid_hw_output_report: %d", err); 689 ASSERT_EQ(errno, 25) TH_LOG("unexpected error code while sending hid_hw_output_report: %d", 690 errno); 691 692 /* remove our bpf program and check that we can now emit commands */ 693 694 /* detach the program */ 695 detach_bpf(self); 696 697 self->hidraw_fd = open_hidraw(&self->hid); 698 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw"); 699 700 err = write(self->hidraw_fd, buf, 3); 701 ASSERT_GE(err, 0) TH_LOG("error while sending hid_hw_output_report: %d", err); 702 } 703 704 /* 705 * Call hid_hw_output_report against the given uhid device, 706 * check that the program is called and can issue the call 707 * to uhid and transform the answer. 708 */ 709 TEST_F(hid_bpf, test_hid_change_output_report_call) 710 { 711 const struct test_program progs[] = { 712 { .name = "hid_test_hidraw_output_report" }, 713 }; 714 __u8 buf[MAX_BUF_SIZE] = {0}; 715 int err; 716 717 LOAD_PROGRAMS(progs); 718 719 /* emit hid_hw_output_report from hidraw */ 720 buf[0] = 1; /* report ID */ 721 buf[1] = 2; 722 buf[2] = 42; 723 724 err = write(self->hidraw_fd, buf, 10); 725 ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d", 726 err); 727 } 728 729 /* 730 * Call hid_hw_output_report against the given uhid device, 731 * check that the program is not making infinite loops. 732 */ 733 TEST_F(hid_bpf, test_hid_infinite_loop_output_report_call) 734 { 735 const struct test_program progs[] = { 736 { .name = "hid_test_infinite_loop_output_report" }, 737 }; 738 __u8 buf[MAX_BUF_SIZE] = {0}; 739 int err; 740 741 LOAD_PROGRAMS(progs); 742 743 /* emit hid_hw_output_report from hidraw */ 744 buf[0] = 1; /* report ID */ 745 buf[1] = 2; 746 buf[2] = 42; 747 748 err = write(self->hidraw_fd, buf, 8); 749 ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d", 750 err); 751 } 752 753 /* 754 * Attach hid_multiply_event_wq to the given uhid device, 755 * retrieve and open the matching hidraw node, 756 * inject one event in the uhid device, 757 * check that the program sees it and can add extra data 758 */ 759 TEST_F(hid_bpf, test_multiply_events_wq) 760 { 761 const struct test_program progs[] = { 762 { .name = "hid_test_multiply_events_wq" }, 763 }; 764 __u8 buf[MAX_BUF_SIZE] = {0}; 765 int err; 766 767 LOAD_PROGRAMS(progs); 768 769 /* inject one event */ 770 buf[0] = 1; 771 buf[1] = 42; 772 uhid_send_event(_metadata, &self->hid, buf, 6); 773 774 /* read the data from hidraw */ 775 memset(buf, 0, sizeof(buf)); 776 err = read(self->hidraw_fd, buf, sizeof(buf)); 777 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 778 ASSERT_EQ(buf[0], 1); 779 ASSERT_EQ(buf[1], 47); 780 781 usleep(100000); 782 783 /* read the data from hidraw */ 784 memset(buf, 0, sizeof(buf)); 785 err = read(self->hidraw_fd, buf, sizeof(buf)); 786 ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); 787 ASSERT_EQ(buf[0], 2); 788 ASSERT_EQ(buf[1], 3); 789 } 790 791 /* 792 * Attach hid_multiply_event to the given uhid device, 793 * retrieve and open the matching hidraw node, 794 * inject one event in the uhid device, 795 * check that the program sees it and can add extra data 796 */ 797 TEST_F(hid_bpf, test_multiply_events) 798 { 799 const struct test_program progs[] = { 800 { .name = "hid_test_multiply_events" }, 801 }; 802 __u8 buf[MAX_BUF_SIZE] = {0}; 803 int err; 804 805 LOAD_PROGRAMS(progs); 806 807 /* inject one event */ 808 buf[0] = 1; 809 buf[1] = 42; 810 uhid_send_event(_metadata, &self->hid, buf, 6); 811 812 /* read the data from hidraw */ 813 memset(buf, 0, sizeof(buf)); 814 err = read(self->hidraw_fd, buf, sizeof(buf)); 815 ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); 816 ASSERT_EQ(buf[0], 2); 817 ASSERT_EQ(buf[1], 47); 818 819 /* read the data from hidraw */ 820 memset(buf, 0, sizeof(buf)); 821 err = read(self->hidraw_fd, buf, sizeof(buf)); 822 ASSERT_EQ(err, 9) TH_LOG("read_hidraw"); 823 ASSERT_EQ(buf[0], 2); 824 ASSERT_EQ(buf[1], 52); 825 } 826 827 /* 828 * Call hid_bpf_input_report against the given uhid device, 829 * check that the program is not making infinite loops. 830 */ 831 TEST_F(hid_bpf, test_hid_infinite_loop_input_report_call) 832 { 833 const struct test_program progs[] = { 834 { .name = "hid_test_infinite_loop_input_report" }, 835 }; 836 __u8 buf[MAX_BUF_SIZE] = {0}; 837 int err; 838 839 LOAD_PROGRAMS(progs); 840 841 /* emit hid_hw_output_report from hidraw */ 842 buf[0] = 1; /* report ID */ 843 buf[1] = 2; 844 buf[2] = 42; 845 846 uhid_send_event(_metadata, &self->hid, buf, 6); 847 848 /* read the data from hidraw */ 849 memset(buf, 0, sizeof(buf)); 850 err = read(self->hidraw_fd, buf, sizeof(buf)); 851 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 852 ASSERT_EQ(buf[0], 1); 853 ASSERT_EQ(buf[1], 3); 854 855 /* read the data from hidraw: hid_bpf_try_input_report should work exactly one time */ 856 memset(buf, 0, sizeof(buf)); 857 err = read(self->hidraw_fd, buf, sizeof(buf)); 858 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 859 ASSERT_EQ(buf[0], 1); 860 ASSERT_EQ(buf[1], 4); 861 862 /* read the data from hidraw: there should be none */ 863 memset(buf, 0, sizeof(buf)); 864 err = read(self->hidraw_fd, buf, sizeof(buf)); 865 ASSERT_EQ(err, -1) TH_LOG("read_hidraw"); 866 } 867 868 /* 869 * Attach hid_insert{0,1,2} to the given uhid device, 870 * retrieve and open the matching hidraw node, 871 * inject one event in the uhid device, 872 * check that the programs have been inserted in the correct order. 873 */ 874 TEST_F(hid_bpf, test_hid_attach_flags) 875 { 876 const struct test_program progs[] = { 877 { 878 .name = "hid_test_insert2", 879 .insert_head = 0, 880 }, 881 { 882 .name = "hid_test_insert1", 883 .insert_head = 1, 884 }, 885 { 886 .name = "hid_test_insert3", 887 .insert_head = 0, 888 }, 889 }; 890 __u8 buf[MAX_BUF_SIZE] = {0}; 891 int err; 892 893 LOAD_PROGRAMS(progs); 894 895 /* inject one event */ 896 buf[0] = 1; 897 uhid_send_event(_metadata, &self->hid, buf, 6); 898 899 /* read the data from hidraw */ 900 memset(buf, 0, sizeof(buf)); 901 err = read(self->hidraw_fd, buf, sizeof(buf)); 902 ASSERT_EQ(err, 6) TH_LOG("read_hidraw"); 903 ASSERT_EQ(buf[1], 1); 904 ASSERT_EQ(buf[2], 2); 905 ASSERT_EQ(buf[3], 3); 906 } 907 908 /* 909 * Attach hid_rdesc_fixup to the given uhid device, 910 * retrieve and open the matching hidraw node, 911 * check that the hidraw report descriptor has been updated. 912 */ 913 TEST_F(hid_bpf, test_rdesc_fixup) 914 { 915 struct hidraw_report_descriptor rpt_desc = {0}; 916 const struct test_program progs[] = { 917 { .name = "hid_rdesc_fixup" }, 918 }; 919 int err, desc_size; 920 921 if (variant->rdesc != rdesc) 922 SKIP(return, "not compatible report descriptor"); 923 924 LOAD_PROGRAMS(progs); 925 926 /* check that hid_rdesc_fixup() was executed */ 927 ASSERT_EQ(self->skel->data->callback2_check, 0x21); 928 929 /* read the exposed report descriptor from hidraw */ 930 err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size); 931 ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESCSIZE: %d", err); 932 933 /* ensure the new size of the rdesc is bigger than the old one */ 934 ASSERT_GT(desc_size, sizeof(rdesc)); 935 936 rpt_desc.size = desc_size; 937 err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &rpt_desc); 938 ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESC: %d", err); 939 940 ASSERT_EQ(rpt_desc.value[4], 0x42); 941 } 942 943 TEST_F(hid_bpf, test_rdesc_fixup_get_data_overflow) 944 { 945 const struct test_program progs[] = { 946 { .name = "hid_rdesc_fixup_get_data_overflow" }, 947 }; 948 949 /* newer verifier can detect the overflow at load time */ 950 if (LOAD_PROGRAMS_MAY_FAIL(progs)) 951 return; 952 953 ASSERT_EQ(self->skel->bss->get_data_overflow_check, 1); 954 } 955 956 TEST_F(hid_bpf, test_rdesc_fixup_change_uniq_name_phys) 957 { 958 const struct test_program progs[] = { 959 { .name = "hid_rdesc_fixup_change_uniq_name_phys" }, 960 }; 961 char expected[256], buf[256] = {}; 962 int err; 963 964 LOAD_PROGRAMS(progs); 965 966 err = ioctl(self->hidraw_fd, HIDIOCGRAWNAME(sizeof(buf)), buf); 967 ASSERT_GE(err, 0) TH_LOG("HIDIOCGRAWNAME"); 968 ASSERT_STREQ("name coming from bpf", buf); 969 970 snprintf(expected, sizeof(expected), "%d phys:coming:from:bpf", self->hid.dev_id); 971 972 err = ioctl(self->hidraw_fd, HIDIOCGRAWPHYS(sizeof(buf)), buf); 973 ASSERT_GE(err, 0) TH_LOG("HIDIOCGRAWPHYS"); 974 ASSERT_STREQ(expected, buf); 975 976 err = ioctl(self->hidraw_fd, HIDIOCGRAWUNIQ(sizeof(buf)), buf); 977 ASSERT_GE(err, 0) TH_LOG("HIDIOCGRAWUNIQ"); 978 ASSERT_STREQ("uniq:coming:from:bpf", buf); 979 980 } 981 982 static int libbpf_print_fn(enum libbpf_print_level level, 983 const char *format, va_list args) 984 { 985 char buf[1024]; 986 987 if (level == LIBBPF_DEBUG) 988 return 0; 989 990 snprintf(buf, sizeof(buf), "# %s", format); 991 992 vfprintf(stdout, buf, args); 993 return 0; 994 } 995 996 int main(int argc, char **argv) 997 { 998 /* Use libbpf 1.0 API mode */ 999 libbpf_set_strict_mode(LIBBPF_STRICT_ALL); 1000 libbpf_set_print(libbpf_print_fn); 1001 1002 return test_harness_run(argc, argv); 1003 } 1004