hid_bpf.c 23 KB

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