mbox series

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

Message ID 20221124151603.807536-1-benjamin.tissoires@redhat.com (mailing list archive)
Headers show
Series HID-BPF: add support for in-tree BPF programs | expand

Message

Benjamin Tissoires Nov. 24, 2022, 3:15 p.m. UTC
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