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