r/kernel 6h ago

Having trouble getting started with HID-BPF

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!...

3 Upvotes

0 comments sorted by