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