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