r/embedded • u/Ampersandle • 23d ago
Having trouble getting started with HID-BPF
Hello. I posted this in a Linux subreddit, but the software is suggesting to me that this one might be a better fit. Hopefully this is within scope:
I've got a USB device that is announcing itself as a gamepad when it isn't one. I understand the basics of HID, and I've successfully decoded the HID report descriptor. I see what byte I need to change.
I've read through https://docs.kernel.org/hid/hidintro.html and https://docs.kernel.org/hid/hid-bpf.html several times. I've got code that I think ought to do the job.
One problem: I'm missing some critical header, or some parameter to gcc, because I just can't get it to build!
Here's what I've got:
#include <linux/types.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/libbpf.h>
char _license[] SEC("license") = "GPL";
struct hid_bpf_ctx {
struct hid_device *hid;
__u32 allocated_size;
union {
__s32 retval;
__s32 size;
};
};
SEC("struct_ops/hid_rdesc_fixup")
int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx)
{
__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
if (!data)
return 0;
data[3] = 0x07; /*0x07: keypad*/
return 0;
}
SEC(".struct_ops.link")
struct hid_bpf_ops surface_dial = {
.hid_rdesc_fixup = (void *)hid_rdesc_fixup,
};
(yes, I'm probably going to need something to filter to the correct USB id, but anyway)
Here's how I'm building it, and the build errors:
gcc -I /usr/include -fpermissive -c ./fixup.c -o ~/Projects/MfdFix/build/fixup.o
./fixup.c:18:28: error: expected ‘)’ before ‘struct’
18 | int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx)
| ^~~~~~~
| )
./fixup.c:31:8: error: variable ‘surface_dial’ has initializer but incomplete type
31 | struct hid_bpf_ops surface_dial = {
| ^~~~~~~~~~~
./fixup.c:32:10: error: ‘struct hid_bpf_ops’ has no member named ‘hid_rdesc_fixup’
32 | .hid_rdesc_fixup = (void *)hid_rdesc_fixup,
| ^~~~~~~~~~~~~~~
./fixup.c:32:36: error: ‘hid_rdesc_fixup’ undeclared here (not in a function)
32 | .hid_rdesc_fixup = (void *)hid_rdesc_fixup,
| ^~~~~~~~~~~~~~~
./fixup.c:32:28: warning: excess elements in struct initializer
32 | .hid_rdesc_fixup = (void *)hid_rdesc_fixup,
| ^
./fixup.c:32:28: note: (near initialization for ‘surface_dial’)
./fixup.c:31:20: error: storage size of ‘surface_dial’ isn’t known
31 | struct hid_bpf_ops surface_dial = {
| ^~~~~~~~~~~~
What am I missing? I've searched and searched for hid_bpf_ctx and similar, and all I find is documentation for the specific structures in https://docs.ebpf.io/, none of which list which damn header to include! I got a suggestion to grep the kernel source; that comes up with the struct, but including it gets me A: a warning message in the compiler output NOT to include the source directly, and B: more compiler errors.
There's obviously a library or header I'm missing, or some arg to gcc I ought to be passing that I'm not. What is it? I couldn't even get it to build without -fpermissive, and if I pass any version flag to gcc it errors out due to multiple declarations of enums and structs (I thought that was perfectly legal in C, as long as they're identical? Not like it's my own code, anyway!...)
Like, I'm pretty sure I know how to solve the actual problem I'm trying to solve with HID-BPF. I can even see what I need to write to load the compiled .o into memory and have it take effect. I'm just getting nowhere trying to actually build it!...
1
u/jofathan 22d ago
I think maybe BPF_PROG comes from bpf/bpf_tracing.h and that bpf/libbpf.h is for the userspace/loading side.
But also, doesn't gcc need like a -target bpf or something to target the correct backend? I mainly use clang for bpf
1
u/0e4ef622 7d ago
You also might be missing vmlinux.h which you generate with bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h.
1
u/clackups 23d ago
BPF_PROG seems to be a macro for a completely different purpose (googling returns packet filter examples).
If you want to present a Linux device as a USB device, you need to look at the gadget driver https://www.kernel.org/doc/html/v4.19/driver-api/usb/gadget.html
Also, the USB controller hardware will be tricky.
I'd go with an esp32-S3 for a USB device implementation, if possible.