Re: [PATCH bpf-next v3 06/17] HID: allow to change the report descriptor from an eBPF program

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Alexei,

On Tue, Mar 22, 2022 at 11:51 PM Alexei Starovoitov
<alexei.starovoitov@xxxxxxxxx> wrote:
>
> On Fri, Mar 18, 2022 at 9:16 AM Benjamin Tissoires
> <benjamin.tissoires@xxxxxxxxxx> wrote:
> >
> > +u8 *hid_bpf_report_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size)
> > +{
> > +       int ret;
> > +       struct hid_bpf_ctx_kern ctx = {
> > +               .type = HID_BPF_RDESC_FIXUP,
> > +               .hdev = hdev,
> > +               .size = *size,
> > +       };
> > +
> > +       if (bpf_hid_link_empty(&hdev->bpf, BPF_HID_ATTACH_RDESC_FIXUP))
> > +               goto ignore_bpf;
> > +
> > +       ctx.data = kmemdup(rdesc, HID_MAX_DESCRIPTOR_SIZE, GFP_KERNEL);
> > +       if (!ctx.data)
> > +               goto ignore_bpf;
> > +
> > +       ctx.allocated_size = HID_MAX_DESCRIPTOR_SIZE;
> > +
> > +       ret = hid_bpf_run_progs(hdev, &ctx);
> > +       if (ret)
> > +               goto ignore_bpf;
> > +
> > +       if (ctx.size > ctx.allocated_size)
> > +               goto ignore_bpf;
> > +
> > +       *size = ctx.size;
> > +
> > +       if (*size) {
> > +               rdesc = krealloc(ctx.data, *size, GFP_KERNEL);
> > +       } else {
> > +               rdesc = NULL;
> > +               kfree(ctx.data);
> > +       }
> > +
> > +       return rdesc;
> > +
> > + ignore_bpf:
> > +       kfree(ctx.data);
> > +       return kmemdup(rdesc, *size, GFP_KERNEL);
> > +}
> > +
> >  int __init hid_bpf_module_init(void)
> >  {
> >         struct bpf_hid_hooks hooks = {
> >                 .hdev_from_fd = hid_bpf_fd_to_hdev,
> >                 .pre_link_attach = hid_bpf_pre_link_attach,
> > +               .post_link_attach = hid_bpf_post_link_attach,
> >                 .array_detach = hid_bpf_array_detach,
> >         };
> >
> > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> > index 937fab7eb9c6..3182c39db006 100644
> > --- a/drivers/hid/hid-core.c
> > +++ b/drivers/hid/hid-core.c
> > @@ -1213,7 +1213,8 @@ int hid_open_report(struct hid_device *device)
> >                 return -ENODEV;
> >         size = device->dev_rsize;
> >
> > -       buf = kmemdup(start, size, GFP_KERNEL);
> > +       /* hid_bpf_report_fixup() ensures we work on a copy of rdesc */
> > +       buf = hid_bpf_report_fixup(device, start, &size);
>
> Looking at this patch and the majority of other patches...
> the code is doing a lot of work to connect HID side with bpf.
> At the same time the evolution of the patch series suggests
> that these hook points are not quite stable. More hooks and
> helpers are being added.
> It tells us that it's way too early to introduce a stable
> interface between HID and bpf.

I understand that you might be under the impression that the interface
is changing a lot, but this is mostly due to my poor knowledge of all
the arcanes of eBPF.
The overall way HID-BPF works is to work on a single array, and we
should pretty much be sorted out. There are a couple of helpers to be
able to communicate with the device, but the API has been stable in
the kernel for those for quite some time now.

The variations in the hooks is mostly because I don't know what is the
best representation we can use in eBPF for those, and the review
process is changing that.

> We suggest to use __weak global functions and unstable kfunc helpers
> to achieve the same goal.
> This way HID side and bpf side can evolve without introducing
> stable uapi burden.
> For example this particular patch can be compressed to:
> __weak int hid_bpf_report_fixup(struct hid_device *hdev, u8 *rdesc,
> unsigned int *size)
> {
>    return 0;
> }
> ALLOW_ERROR_INJECTION(ALLOW_ERROR_INJECTION, ERRNO);
>
> - buf = kmemdup(start, size, GFP_KERNEL);
> + if (!hid_bpf_report_fixup(device, start, &size))
> +   buf = kmemdup(start, size, GFP_KERNEL);
>
> Then bpf program can replace hid_bpf_report_fixup function and adjust its
> return value while reading args.

I appreciate the suggestion and gave it a try, but AFAICT this doesn't
work for HID (please correct me if I am wrong):

- I tried to use __weak to replace the ugly struct bpf_hid_hooks

This struct is in place simply because the HID module can be compiled
in as a kernel module and we might not have the symbols available from
kernel/bpf when it is a separate module.
Either I did something wrong, but it seems that when we load the
module in the kernel, there is no magic that overrides the weak
symbols from the ones from the modules.

- for hid_bpf_report_fixup(), this would mean that a BPF program could
overwrite the function

This is great, but I need to have one program per device, not one
globally defined function.
I can not have a generic report_fixup in the system, simply because
you might need 2 different functions for 2 different devices.

We could solve that by auto-generating the bpf program based on which
devices are available, but that would mean that users will see a
reconnect of all of their input devices when they plug in a new one,
and will also require them to have LLVM installed, which I do not
want.

- for stuff like hid_bpf_raw_event(), I want to have multiple programs
attached to the various devices, and not necessarily the same across
devices.

This is basically the same as above, except that I need to chain programs.

For instance, we could have a program that "fixes" one device, but I
also want to attach a tracing program on top of it to monitor what is
happening.

>
> Similar approach can be done with all other hooks.
>
> Once api between HID and bpf stabilizes we can replace nop functions
> with writeable tracepoints to make things a bit more stable
> while still allowing for change of the interface in the future.
>
> The amount of bpf specific code in HID core will be close to zero
> while bpf can be used to flexibly tweak it.

Again, I like the idea, but I clearly don't see where you want to go.

[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux