Path: blob/master/tools/testing/selftests/hid/hid_bpf.c
26302 views
// SPDX-License-Identifier: GPL-2.01/* Copyright (c) 2022-2024 Red Hat */2#include "hid.skel.h"3#include "hid_common.h"4#include <bpf/bpf.h>56struct hid_hw_request_syscall_args {7__u8 data[10];8unsigned int hid;9int retval;10size_t size;11enum hid_report_type type;12__u8 request_type;13};1415FIXTURE(hid_bpf) {16struct uhid_device hid;17int hidraw_fd;18struct hid *skel;19struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */20};21static void detach_bpf(FIXTURE_DATA(hid_bpf) * self)22{23int i;2425if (self->hidraw_fd)26close(self->hidraw_fd);27self->hidraw_fd = 0;2829if (!self->skel)30return;3132hid__detach(self->skel);3334for (i = 0; i < ARRAY_SIZE(self->hid_links); i++) {35if (self->hid_links[i])36bpf_link__destroy(self->hid_links[i]);37}3839hid__destroy(self->skel);40self->skel = NULL;41}4243FIXTURE_TEARDOWN(hid_bpf) {44void *uhid_err;4546uhid_destroy(_metadata, &self->hid);4748detach_bpf(self);49pthread_join(self->hid.tid, &uhid_err);50}51#define TEARDOWN_LOG(fmt, ...) do { \52TH_LOG(fmt, ##__VA_ARGS__); \53hid_bpf_teardown(_metadata, self, variant); \54} while (0)5556FIXTURE_SETUP(hid_bpf)57{58int err;5960err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a36, rdesc, sizeof(rdesc));61ASSERT_OK(err);62}6364struct test_program {65const char *name;66int insert_head;67};68#define LOAD_PROGRAMS(progs) \69load_programs(progs, ARRAY_SIZE(progs), _metadata, self, variant)70#define LOAD_BPF \71load_programs(NULL, 0, _metadata, self, variant)72static void load_programs(const struct test_program programs[],73const size_t progs_count,74struct __test_metadata *_metadata,75FIXTURE_DATA(hid_bpf) * self,76const FIXTURE_VARIANT(hid_bpf) * variant)77{78struct bpf_map *iter_map;79int err = -EINVAL;8081ASSERT_LE(progs_count, ARRAY_SIZE(self->hid_links))82TH_LOG("too many programs are to be loaded");8384/* open the bpf file */85self->skel = hid__open();86ASSERT_OK_PTR(self->skel) TEARDOWN_LOG("Error while calling hid__open");8788for (int i = 0; i < progs_count; i++) {89struct bpf_program *prog;90struct bpf_map *map;91int *ops_hid_id;9293prog = bpf_object__find_program_by_name(*self->skel->skeleton->obj,94programs[i].name);95ASSERT_OK_PTR(prog) TH_LOG("can not find program by name '%s'", programs[i].name);9697bpf_program__set_autoload(prog, true);9899map = bpf_object__find_map_by_name(*self->skel->skeleton->obj,100programs[i].name + 4);101ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'",102programs[i].name + 4);103104/* hid_id is the first field of struct hid_bpf_ops */105ops_hid_id = bpf_map__initial_value(map, NULL);106ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data");107108*ops_hid_id = self->hid.hid_id;109}110111/* we disable the auto-attach feature of all maps because we112* only want the tested one to be manually attached in the next113* call to bpf_map__attach_struct_ops()114*/115bpf_object__for_each_map(iter_map, *self->skel->skeleton->obj)116bpf_map__set_autoattach(iter_map, false);117118err = hid__load(self->skel);119ASSERT_OK(err) TH_LOG("hid_skel_load failed: %d", err);120121for (int i = 0; i < progs_count; i++) {122struct bpf_map *map;123124map = bpf_object__find_map_by_name(*self->skel->skeleton->obj,125programs[i].name + 4);126ASSERT_OK_PTR(map) TH_LOG("can not find struct_ops by name '%s'",127programs[i].name + 4);128129self->hid_links[i] = bpf_map__attach_struct_ops(map);130ASSERT_OK_PTR(self->hid_links[i]) TH_LOG("failed to attach struct ops '%s'",131programs[i].name + 4);132}133134hid__attach(self->skel);135136self->hidraw_fd = open_hidraw(&self->hid);137ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");138}139140/*141* A simple test to see if the fixture is working fine.142* If this fails, none of the other tests will pass.143*/144TEST_F(hid_bpf, test_create_uhid)145{146}147148/*149* Attach hid_first_event to the given uhid device,150* retrieve and open the matching hidraw node,151* inject one event in the uhid device,152* check that the program sees it and can change the data153*/154TEST_F(hid_bpf, raw_event)155{156const struct test_program progs[] = {157{ .name = "hid_first_event" },158};159__u8 buf[10] = {0};160int err;161162LOAD_PROGRAMS(progs);163164/* check that the program is correctly loaded */165ASSERT_EQ(self->skel->data->callback_check, 52) TH_LOG("callback_check1");166ASSERT_EQ(self->skel->data->callback2_check, 52) TH_LOG("callback2_check1");167168/* inject one event */169buf[0] = 1;170buf[1] = 42;171uhid_send_event(_metadata, &self->hid, buf, 6);172173/* check that hid_first_event() was executed */174ASSERT_EQ(self->skel->data->callback_check, 42) TH_LOG("callback_check1");175176/* read the data from hidraw */177memset(buf, 0, sizeof(buf));178err = read(self->hidraw_fd, buf, sizeof(buf));179ASSERT_EQ(err, 6) TH_LOG("read_hidraw");180ASSERT_EQ(buf[0], 1);181ASSERT_EQ(buf[2], 47);182183/* inject another event */184memset(buf, 0, sizeof(buf));185buf[0] = 1;186buf[1] = 47;187uhid_send_event(_metadata, &self->hid, buf, 6);188189/* check that hid_first_event() was executed */190ASSERT_EQ(self->skel->data->callback_check, 47) TH_LOG("callback_check1");191192/* read the data from hidraw */193memset(buf, 0, sizeof(buf));194err = read(self->hidraw_fd, buf, sizeof(buf));195ASSERT_EQ(err, 6) TH_LOG("read_hidraw");196ASSERT_EQ(buf[2], 52);197}198199/*200* Attach hid_first_event to the given uhid device,201* retrieve and open the matching hidraw node,202* inject one event in the uhid device,203* check that the program sees it and can change the data204*/205TEST_F(hid_bpf, subprog_raw_event)206{207const struct test_program progs[] = {208{ .name = "hid_subprog_first_event" },209};210__u8 buf[10] = {0};211int err;212213LOAD_PROGRAMS(progs);214215/* inject one event */216buf[0] = 1;217buf[1] = 42;218uhid_send_event(_metadata, &self->hid, buf, 6);219220/* read the data from hidraw */221memset(buf, 0, sizeof(buf));222err = read(self->hidraw_fd, buf, sizeof(buf));223ASSERT_EQ(err, 6) TH_LOG("read_hidraw");224ASSERT_EQ(buf[0], 1);225ASSERT_EQ(buf[2], 47);226227/* inject another event */228memset(buf, 0, sizeof(buf));229buf[0] = 1;230buf[1] = 47;231uhid_send_event(_metadata, &self->hid, buf, 6);232233/* read the data from hidraw */234memset(buf, 0, sizeof(buf));235err = read(self->hidraw_fd, buf, sizeof(buf));236ASSERT_EQ(err, 6) TH_LOG("read_hidraw");237ASSERT_EQ(buf[2], 52);238}239240/*241* Attach hid_first_event to the given uhid device,242* attempt at re-attaching it, we should not lock and243* return an invalid struct bpf_link244*/245TEST_F(hid_bpf, multiple_attach)246{247const struct test_program progs[] = {248{ .name = "hid_first_event" },249};250struct bpf_link *link;251252LOAD_PROGRAMS(progs);253254link = bpf_map__attach_struct_ops(self->skel->maps.first_event);255ASSERT_NULL(link) TH_LOG("unexpected return value when re-attaching the struct_ops");256}257258/*259* Ensures that we can attach/detach programs260*/261TEST_F(hid_bpf, test_attach_detach)262{263const struct test_program progs[] = {264{ .name = "hid_first_event" },265{ .name = "hid_second_event" },266};267struct bpf_link *link;268__u8 buf[10] = {0};269int err, link_fd;270271LOAD_PROGRAMS(progs);272273link = self->hid_links[0];274ASSERT_OK_PTR(link) TH_LOG("HID-BPF link not created");275276link_fd = bpf_link__fd(link);277ASSERT_GE(link_fd, 0) TH_LOG("HID-BPF link FD not valid");278279/* inject one event */280buf[0] = 1;281buf[1] = 42;282uhid_send_event(_metadata, &self->hid, buf, 6);283284/* read the data from hidraw */285memset(buf, 0, sizeof(buf));286err = read(self->hidraw_fd, buf, sizeof(buf));287ASSERT_EQ(err, 6) TH_LOG("read_hidraw");288ASSERT_EQ(buf[0], 1);289ASSERT_EQ(buf[2], 47);290291/* make sure both programs are run */292ASSERT_EQ(buf[3], 52);293294/* pin the first program and immediately unpin it */295#define PIN_PATH "/sys/fs/bpf/hid_first_event"296err = bpf_obj_pin(link_fd, PIN_PATH);297ASSERT_OK(err) TH_LOG("error while calling bpf_obj_pin");298remove(PIN_PATH);299#undef PIN_PATH300usleep(100000);301302/* detach the program */303detach_bpf(self);304305self->hidraw_fd = open_hidraw(&self->hid);306ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");307308/* inject another event */309memset(buf, 0, sizeof(buf));310buf[0] = 1;311buf[1] = 47;312uhid_send_event(_metadata, &self->hid, buf, 6);313314/* read the data from hidraw */315memset(buf, 0, sizeof(buf));316err = read(self->hidraw_fd, buf, sizeof(buf));317ASSERT_EQ(err, 6) TH_LOG("read_hidraw_no_bpf");318ASSERT_EQ(buf[0], 1);319ASSERT_EQ(buf[1], 47);320ASSERT_EQ(buf[2], 0);321ASSERT_EQ(buf[3], 0);322323/* re-attach our program */324325LOAD_PROGRAMS(progs);326327/* inject one event */328memset(buf, 0, sizeof(buf));329buf[0] = 1;330buf[1] = 42;331uhid_send_event(_metadata, &self->hid, buf, 6);332333/* read the data from hidraw */334memset(buf, 0, sizeof(buf));335err = read(self->hidraw_fd, buf, sizeof(buf));336ASSERT_EQ(err, 6) TH_LOG("read_hidraw");337ASSERT_EQ(buf[0], 1);338ASSERT_EQ(buf[2], 47);339ASSERT_EQ(buf[3], 52);340}341342/*343* Attach hid_change_report_id to the given uhid device,344* retrieve and open the matching hidraw node,345* inject one event in the uhid device,346* check that the program sees it and can change the data347*/348TEST_F(hid_bpf, test_hid_change_report)349{350const struct test_program progs[] = {351{ .name = "hid_change_report_id" },352};353__u8 buf[10] = {0};354int err;355356LOAD_PROGRAMS(progs);357358/* inject one event */359buf[0] = 1;360buf[1] = 42;361uhid_send_event(_metadata, &self->hid, buf, 6);362363/* read the data from hidraw */364memset(buf, 0, sizeof(buf));365err = read(self->hidraw_fd, buf, sizeof(buf));366ASSERT_EQ(err, 9) TH_LOG("read_hidraw");367ASSERT_EQ(buf[0], 2);368ASSERT_EQ(buf[1], 42);369ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");370}371372/*373* Call hid_bpf_input_report against the given uhid device,374* check that the program is called and does the expected.375*/376TEST_F(hid_bpf, test_hid_user_input_report_call)377{378struct hid_hw_request_syscall_args args = {379.retval = -1,380.size = 10,381};382DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,383.ctx_in = &args,384.ctx_size_in = sizeof(args),385);386__u8 buf[10] = {0};387int err, prog_fd;388389LOAD_BPF;390391args.hid = self->hid.hid_id;392args.data[0] = 1; /* report ID */393args.data[1] = 2; /* report ID */394args.data[2] = 42; /* report ID */395396prog_fd = bpf_program__fd(self->skel->progs.hid_user_input_report);397398/* check that there is no data to read from hidraw */399memset(buf, 0, sizeof(buf));400err = read(self->hidraw_fd, buf, sizeof(buf));401ASSERT_EQ(err, -1) TH_LOG("read_hidraw");402403err = bpf_prog_test_run_opts(prog_fd, &tattrs);404405ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");406407ASSERT_EQ(args.retval, 0);408409/* read the data from hidraw */410memset(buf, 0, sizeof(buf));411err = read(self->hidraw_fd, buf, sizeof(buf));412ASSERT_EQ(err, 6) TH_LOG("read_hidraw");413ASSERT_EQ(buf[0], 1);414ASSERT_EQ(buf[1], 2);415ASSERT_EQ(buf[2], 42);416}417418/*419* Call hid_bpf_hw_output_report against the given uhid device,420* check that the program is called and does the expected.421*/422TEST_F(hid_bpf, test_hid_user_output_report_call)423{424struct hid_hw_request_syscall_args args = {425.retval = -1,426.size = 10,427};428DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,429.ctx_in = &args,430.ctx_size_in = sizeof(args),431);432int err, cond_err, prog_fd;433struct timespec time_to_wait;434435LOAD_BPF;436437args.hid = self->hid.hid_id;438args.data[0] = 1; /* report ID */439args.data[1] = 2; /* report ID */440args.data[2] = 42; /* report ID */441442prog_fd = bpf_program__fd(self->skel->progs.hid_user_output_report);443444pthread_mutex_lock(&uhid_output_mtx);445446memset(output_report, 0, sizeof(output_report));447clock_gettime(CLOCK_REALTIME, &time_to_wait);448time_to_wait.tv_sec += 2;449450err = bpf_prog_test_run_opts(prog_fd, &tattrs);451cond_err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);452453ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");454ASSERT_OK(cond_err) TH_LOG("error while calling waiting for the condition");455456ASSERT_EQ(args.retval, 3);457458ASSERT_EQ(output_report[0], 1);459ASSERT_EQ(output_report[1], 2);460ASSERT_EQ(output_report[2], 42);461462pthread_mutex_unlock(&uhid_output_mtx);463}464465/*466* Call hid_hw_raw_request against the given uhid device,467* check that the program is called and does the expected.468*/469TEST_F(hid_bpf, test_hid_user_raw_request_call)470{471struct hid_hw_request_syscall_args args = {472.retval = -1,473.type = HID_FEATURE_REPORT,474.request_type = HID_REQ_GET_REPORT,475.size = 10,476};477DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,478.ctx_in = &args,479.ctx_size_in = sizeof(args),480);481int err, prog_fd;482483LOAD_BPF;484485args.hid = self->hid.hid_id;486args.data[0] = 1; /* report ID */487488prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request);489490err = bpf_prog_test_run_opts(prog_fd, &tattrs);491ASSERT_OK(err) TH_LOG("error while calling bpf_prog_test_run_opts");492493ASSERT_EQ(args.retval, 2);494495ASSERT_EQ(args.data[1], 2);496}497498/*499* Call hid_hw_raw_request against the given uhid device,500* check that the program is called and prevents the501* call to uhid.502*/503TEST_F(hid_bpf, test_hid_filter_raw_request_call)504{505const struct test_program progs[] = {506{ .name = "hid_test_filter_raw_request" },507};508__u8 buf[10] = {0};509int err;510511LOAD_PROGRAMS(progs);512513/* first check that we did not attach to device_event */514515/* inject one event */516buf[0] = 1;517buf[1] = 42;518uhid_send_event(_metadata, &self->hid, buf, 6);519520/* read the data from hidraw */521memset(buf, 0, sizeof(buf));522err = read(self->hidraw_fd, buf, sizeof(buf));523ASSERT_EQ(err, 6) TH_LOG("read_hidraw");524ASSERT_EQ(buf[0], 1);525ASSERT_EQ(buf[1], 42);526ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");527528/* now check that our program is preventing hid_hw_raw_request() */529530/* emit hid_hw_raw_request from hidraw */531/* Get Feature */532memset(buf, 0, sizeof(buf));533buf[0] = 0x1; /* Report Number */534err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);535ASSERT_LT(err, 0) TH_LOG("unexpected success while reading HIDIOCGFEATURE: %d", err);536ASSERT_EQ(errno, 20) TH_LOG("unexpected error code while reading HIDIOCGFEATURE: %d",537errno);538539/* remove our bpf program and check that we can now emit commands */540541/* detach the program */542detach_bpf(self);543544self->hidraw_fd = open_hidraw(&self->hid);545ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");546547err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);548ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGFEATURE: %d", err);549}550551/*552* Call hid_hw_raw_request against the given uhid device,553* check that the program is called and can issue the call554* to uhid and transform the answer.555*/556TEST_F(hid_bpf, test_hid_change_raw_request_call)557{558const struct test_program progs[] = {559{ .name = "hid_test_hidraw_raw_request" },560};561__u8 buf[10] = {0};562int err;563564LOAD_PROGRAMS(progs);565566/* emit hid_hw_raw_request from hidraw */567/* Get Feature */568memset(buf, 0, sizeof(buf));569buf[0] = 0x1; /* Report Number */570err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);571ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err);572573ASSERT_EQ(buf[0], 2);574ASSERT_EQ(buf[1], 3);575ASSERT_EQ(buf[2], 4);576}577578/*579* Call hid_hw_raw_request against the given uhid device,580* check that the program is not making infinite loops.581*/582TEST_F(hid_bpf, test_hid_infinite_loop_raw_request_call)583{584const struct test_program progs[] = {585{ .name = "hid_test_infinite_loop_raw_request" },586};587__u8 buf[10] = {0};588int err;589590LOAD_PROGRAMS(progs);591592/* emit hid_hw_raw_request from hidraw */593/* Get Feature */594memset(buf, 0, sizeof(buf));595buf[0] = 0x1; /* Report Number */596err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);597ASSERT_EQ(err, 3) TH_LOG("unexpected returned size while reading HIDIOCGFEATURE: %d", err);598}599600/*601* Call hid_hw_output_report against the given uhid device,602* check that the program is called and prevents the603* call to uhid.604*/605TEST_F(hid_bpf, test_hid_filter_output_report_call)606{607const struct test_program progs[] = {608{ .name = "hid_test_filter_output_report" },609};610__u8 buf[10] = {0};611int err;612613LOAD_PROGRAMS(progs);614615/* first check that we did not attach to device_event */616617/* inject one event */618buf[0] = 1;619buf[1] = 42;620uhid_send_event(_metadata, &self->hid, buf, 6);621622/* read the data from hidraw */623memset(buf, 0, sizeof(buf));624err = read(self->hidraw_fd, buf, sizeof(buf));625ASSERT_EQ(err, 6) TH_LOG("read_hidraw");626ASSERT_EQ(buf[0], 1);627ASSERT_EQ(buf[1], 42);628ASSERT_EQ(buf[2], 0) TH_LOG("leftovers_from_previous_test");629630/* now check that our program is preventing hid_hw_output_report() */631632buf[0] = 1; /* report ID */633buf[1] = 2;634buf[2] = 42;635636err = write(self->hidraw_fd, buf, 3);637ASSERT_LT(err, 0) TH_LOG("unexpected success while sending hid_hw_output_report: %d", err);638ASSERT_EQ(errno, 25) TH_LOG("unexpected error code while sending hid_hw_output_report: %d",639errno);640641/* remove our bpf program and check that we can now emit commands */642643/* detach the program */644detach_bpf(self);645646self->hidraw_fd = open_hidraw(&self->hid);647ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");648649err = write(self->hidraw_fd, buf, 3);650ASSERT_GE(err, 0) TH_LOG("error while sending hid_hw_output_report: %d", err);651}652653/*654* Call hid_hw_output_report against the given uhid device,655* check that the program is called and can issue the call656* to uhid and transform the answer.657*/658TEST_F(hid_bpf, test_hid_change_output_report_call)659{660const struct test_program progs[] = {661{ .name = "hid_test_hidraw_output_report" },662};663__u8 buf[10] = {0};664int err;665666LOAD_PROGRAMS(progs);667668/* emit hid_hw_output_report from hidraw */669buf[0] = 1; /* report ID */670buf[1] = 2;671buf[2] = 42;672673err = write(self->hidraw_fd, buf, 10);674ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d",675err);676}677678/*679* Call hid_hw_output_report against the given uhid device,680* check that the program is not making infinite loops.681*/682TEST_F(hid_bpf, test_hid_infinite_loop_output_report_call)683{684const struct test_program progs[] = {685{ .name = "hid_test_infinite_loop_output_report" },686};687__u8 buf[10] = {0};688int err;689690LOAD_PROGRAMS(progs);691692/* emit hid_hw_output_report from hidraw */693buf[0] = 1; /* report ID */694buf[1] = 2;695buf[2] = 42;696697err = write(self->hidraw_fd, buf, 8);698ASSERT_EQ(err, 2) TH_LOG("unexpected returned size while sending hid_hw_output_report: %d",699err);700}701702/*703* Attach hid_multiply_event_wq to the given uhid device,704* retrieve and open the matching hidraw node,705* inject one event in the uhid device,706* check that the program sees it and can add extra data707*/708TEST_F(hid_bpf, test_multiply_events_wq)709{710const struct test_program progs[] = {711{ .name = "hid_test_multiply_events_wq" },712};713__u8 buf[10] = {0};714int err;715716LOAD_PROGRAMS(progs);717718/* inject one event */719buf[0] = 1;720buf[1] = 42;721uhid_send_event(_metadata, &self->hid, buf, 6);722723/* read the data from hidraw */724memset(buf, 0, sizeof(buf));725err = read(self->hidraw_fd, buf, sizeof(buf));726ASSERT_EQ(err, 6) TH_LOG("read_hidraw");727ASSERT_EQ(buf[0], 1);728ASSERT_EQ(buf[1], 47);729730usleep(100000);731732/* read the data from hidraw */733memset(buf, 0, sizeof(buf));734err = read(self->hidraw_fd, buf, sizeof(buf));735ASSERT_EQ(err, 9) TH_LOG("read_hidraw");736ASSERT_EQ(buf[0], 2);737ASSERT_EQ(buf[1], 3);738}739740/*741* Attach hid_multiply_event to the given uhid device,742* retrieve and open the matching hidraw node,743* inject one event in the uhid device,744* check that the program sees it and can add extra data745*/746TEST_F(hid_bpf, test_multiply_events)747{748const struct test_program progs[] = {749{ .name = "hid_test_multiply_events" },750};751__u8 buf[10] = {0};752int err;753754LOAD_PROGRAMS(progs);755756/* inject one event */757buf[0] = 1;758buf[1] = 42;759uhid_send_event(_metadata, &self->hid, buf, 6);760761/* read the data from hidraw */762memset(buf, 0, sizeof(buf));763err = read(self->hidraw_fd, buf, sizeof(buf));764ASSERT_EQ(err, 9) TH_LOG("read_hidraw");765ASSERT_EQ(buf[0], 2);766ASSERT_EQ(buf[1], 47);767768/* read the data from hidraw */769memset(buf, 0, sizeof(buf));770err = read(self->hidraw_fd, buf, sizeof(buf));771ASSERT_EQ(err, 9) TH_LOG("read_hidraw");772ASSERT_EQ(buf[0], 2);773ASSERT_EQ(buf[1], 52);774}775776/*777* Call hid_bpf_input_report against the given uhid device,778* check that the program is not making infinite loops.779*/780TEST_F(hid_bpf, test_hid_infinite_loop_input_report_call)781{782const struct test_program progs[] = {783{ .name = "hid_test_infinite_loop_input_report" },784};785__u8 buf[10] = {0};786int err;787788LOAD_PROGRAMS(progs);789790/* emit hid_hw_output_report from hidraw */791buf[0] = 1; /* report ID */792buf[1] = 2;793buf[2] = 42;794795uhid_send_event(_metadata, &self->hid, buf, 6);796797/* read the data from hidraw */798memset(buf, 0, sizeof(buf));799err = read(self->hidraw_fd, buf, sizeof(buf));800ASSERT_EQ(err, 6) TH_LOG("read_hidraw");801ASSERT_EQ(buf[0], 1);802ASSERT_EQ(buf[1], 3);803804/* read the data from hidraw: hid_bpf_try_input_report should work exactly one time */805memset(buf, 0, sizeof(buf));806err = read(self->hidraw_fd, buf, sizeof(buf));807ASSERT_EQ(err, 6) TH_LOG("read_hidraw");808ASSERT_EQ(buf[0], 1);809ASSERT_EQ(buf[1], 4);810811/* read the data from hidraw: there should be none */812memset(buf, 0, sizeof(buf));813err = read(self->hidraw_fd, buf, sizeof(buf));814ASSERT_EQ(err, -1) TH_LOG("read_hidraw");815}816817/*818* Attach hid_insert{0,1,2} to the given uhid device,819* retrieve and open the matching hidraw node,820* inject one event in the uhid device,821* check that the programs have been inserted in the correct order.822*/823TEST_F(hid_bpf, test_hid_attach_flags)824{825const struct test_program progs[] = {826{827.name = "hid_test_insert2",828.insert_head = 0,829},830{831.name = "hid_test_insert1",832.insert_head = 1,833},834{835.name = "hid_test_insert3",836.insert_head = 0,837},838};839__u8 buf[10] = {0};840int err;841842LOAD_PROGRAMS(progs);843844/* inject one event */845buf[0] = 1;846uhid_send_event(_metadata, &self->hid, buf, 6);847848/* read the data from hidraw */849memset(buf, 0, sizeof(buf));850err = read(self->hidraw_fd, buf, sizeof(buf));851ASSERT_EQ(err, 6) TH_LOG("read_hidraw");852ASSERT_EQ(buf[1], 1);853ASSERT_EQ(buf[2], 2);854ASSERT_EQ(buf[3], 3);855}856857/*858* Attach hid_rdesc_fixup to the given uhid device,859* retrieve and open the matching hidraw node,860* check that the hidraw report descriptor has been updated.861*/862TEST_F(hid_bpf, test_rdesc_fixup)863{864struct hidraw_report_descriptor rpt_desc = {0};865const struct test_program progs[] = {866{ .name = "hid_rdesc_fixup" },867};868int err, desc_size;869870LOAD_PROGRAMS(progs);871872/* check that hid_rdesc_fixup() was executed */873ASSERT_EQ(self->skel->data->callback2_check, 0x21);874875/* read the exposed report descriptor from hidraw */876err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);877ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESCSIZE: %d", err);878879/* ensure the new size of the rdesc is bigger than the old one */880ASSERT_GT(desc_size, sizeof(rdesc));881882rpt_desc.size = desc_size;883err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &rpt_desc);884ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESC: %d", err);885886ASSERT_EQ(rpt_desc.value[4], 0x42);887}888889static int libbpf_print_fn(enum libbpf_print_level level,890const char *format, va_list args)891{892char buf[1024];893894if (level == LIBBPF_DEBUG)895return 0;896897snprintf(buf, sizeof(buf), "# %s", format);898899vfprintf(stdout, buf, args);900return 0;901}902903int main(int argc, char **argv)904{905/* Use libbpf 1.0 API mode */906libbpf_set_strict_mode(LIBBPF_STRICT_ALL);907libbpf_set_print(libbpf_print_fn);908909return test_harness_run(argc, argv);910}911912913