[RFC hid v1 00/10] HID-BPF: add support for in-tree BPF programs

From: Benjamin Tissoires
Date: Thu Nov 24 2022 - 10:17:13 EST


Hi all,

sending this as an RFC because it's not complete, but I'd like to start
the discussion:

While presenting HID-BPF, I always mentioned that device fixes should be
integrated in the kernel. And I am trying to do that in this series.

Load a generic bpf from the kernel:
===================================

The first step is to be able to load that bpf program without knowing
its interface. So I studied the output of the light skeletons and
squized them into a simple C array. Then I wrote a BPF loader based on
that same skeleton, and now I can iterate over an array of BPF programs
and load the ones that match the device.

The step 0 in that translation was to generate a json instead of a
proper C header for the light skeleton. The idea is that I can then
transform that json into whatever I want, without having to mess up with
bpftool. IIRC this was briefly discussed at plumbers, so I hope this is
not too weird.

Pin the program to the bpffs:
=============================

AFAICT, the infrastructure is not completely ready to pin programs from
the kernel itself (outside of bpf_preload).

I encountered a few hiccups and I'd like to know if I am on the correct
path:
- to be able to pin to the bpffs, it first needs to be mounted by
userspace. Should I add some sort of list of already available
programs that would be picked up by the kernel when bpffs is mounted?

- I am not sure the way I added the pinned program is correct: I am
reusing the skeleton of bpf_iter_link_pin_kernel(), but using
kernel_path_create() in the same way bpf_obj_pin_user() does seems
better, though I always get -ENOENT even with bpffs mounted.

- I also need to be able to add a hierarchy of directories in bpffs from
the kernel, and this requires some more code digging... :)

Produce the actual "compiled" bpf program:
==========================================

The current code here relies on the user to run `make` in the
drivers/hid/bpf/progs directory to regenerate the files.
Leaving aside the fact that I need to check on how to make this step
integrated by the generic root-level make, I wonder if using python to
generate that file is OK.

I am not very happy to add a requirement to build the whole kernel, but
OTOH, writing the same tool in C is desperately annoying. I would rather
have a tool written in rust TBH, if rust is now part of the required
toolchain.

Ship the "compiled" bpf programs:
=================================

In this version, the bpf program is embedded in vmlinux, for no other
reasons that splitting that out in a module would require some more
effort before submitting that RFC (and subject to concurrency races when
a device has several interfaces at once).

However, I wonder what should be the final "product":

- In a first pass, I can keep the current form and have a dedicated
kernel module that contains all of the bpf fixes. The kernel would
load it, check for any match, pin the programs, and unload this kernel
module.

This works but isn't very modular as we just enable/ship all of the
fixes or nothing.

- another idea I had, was to rely on the firmware kernel interface. Now
that I have a simple "bpf module" format (or even the json file), I
could "compile" it into a binary and then have the kernel request the
firmware on a device plug. This way we don't load/unload a module at
each plug, and we rely on the existing firmware capabilities.

I really like this idea, but then I wonder how I can ship those
firmwares. I'd like them to be tied to the currently running kernel,
so should I namespace them in the firmware directory on install? Is
there any other way to be able to have 2 or more firmwares depending
on the kernel version?

I think that's it. Again, this series is just a PoC on top of
hid.git/for-6.2/hid-bpf, and I can change everything if I am not headed
to the correct direction.

Cheers,
Benjamin

Benjamin Tissoires (10):
bpftool: generate json output of skeletons
WIP: bpf: allow to pin programs from the kernel when bpffs is mounted
HID: add a tool to convert a bpf source into a generic bpf loader
HID: add the bpf loader that can attach a generic hid-bpf program
HID: add report descriptor override for the X-Keys XK24
selftests: hid: add vmtest.sh
selftests: hid: Add a variant parameter so we can emulate specific
devices
selftests: hid: add XK-24 tests
selftests: hid: ensure the program is correctly pinned
wip: vmtest aarch64

MAINTAINERS | 1 +
drivers/hid/bpf/Makefile | 3 +-
drivers/hid/bpf/hid_bpf_dispatch.c | 3 +-
drivers/hid/bpf/hid_bpf_loader.c | 243 +++++++++++++++
drivers/hid/bpf/progs/Makefile | 105 +++++++
.../bpf/progs/b0003g0001v05F3p0405-xk24.bpf.c | 106 +++++++
.../progs/b0003g0001v05F3p0405-xk24.hidbpf.h | 292 ++++++++++++++++++
drivers/hid/bpf/progs/hid_bpf.h | 15 +
drivers/hid/bpf/progs/hid_bpf_helpers.h | 22 ++
drivers/hid/bpf/progs/hid_bpf_progs.h | 50 +++
drivers/hid/hid-core.c | 2 +
include/linux/bpf.h | 1 +
include/linux/hid_bpf.h | 2 +
kernel/bpf/inode.c | 41 ++-
tools/bpf/bpftool/gen.c | 95 ++++++
tools/hid/build_progs_list.py | 231 ++++++++++++++
tools/testing/selftests/hid/.gitignore | 1 +
tools/testing/selftests/hid/config.aarch64 | 39 +++
tools/testing/selftests/hid/config.common | 241 +++++++++++++++
tools/testing/selftests/hid/config.x86_64 | 4 +
tools/testing/selftests/hid/hid_bpf.c | 150 +++++++--
tools/testing/selftests/hid/vmtest.sh | 286 +++++++++++++++++
22 files changed, 1907 insertions(+), 26 deletions(-)
create mode 100644 drivers/hid/bpf/hid_bpf_loader.c
create mode 100644 drivers/hid/bpf/progs/Makefile
create mode 100644 drivers/hid/bpf/progs/b0003g0001v05F3p0405-xk24.bpf.c
create mode 100644 drivers/hid/bpf/progs/b0003g0001v05F3p0405-xk24.hidbpf.h
create mode 100644 drivers/hid/bpf/progs/hid_bpf.h
create mode 100644 drivers/hid/bpf/progs/hid_bpf_helpers.h
create mode 100644 drivers/hid/bpf/progs/hid_bpf_progs.h
create mode 100755 tools/hid/build_progs_list.py
create mode 100644 tools/testing/selftests/hid/config.aarch64
create mode 100644 tools/testing/selftests/hid/config.common
create mode 100644 tools/testing/selftests/hid/config.x86_64
create mode 100755 tools/testing/selftests/hid/vmtest.sh

--
2.38.1