HID: bpf: move HID-BPF report descriptor fixup earlier
authorBenjamin Tissoires <bentiss@kernel.org>
Tue, 1 Oct 2024 14:30:05 +0000 (16:30 +0200)
committerBenjamin Tissoires <bentiss@kernel.org>
Fri, 4 Oct 2024 14:10:27 +0000 (16:10 +0200)
commit8b7fd6a15f8c32760c2026a62dcf55219b4da15b
tree529362110a1ff8ee137907448f9ee1a98486a4d3
parentf23aa4c0761a70bfd046dd5755281667f0769a94
HID: bpf: move HID-BPF report descriptor fixup earlier

Currently, hid_bpf_rdesc_fixup() is called once the match between the
HID device and the driver is done. This can be problematic in case
the driver selected by the kernel would change the report descriptor
after the fact.

To give a chance for hid_bpf_rdesc_fixup() to provide hints on to how
to select a dedicated driver or not, move the call to that BPF hook
earlier in the .probe() process, when we get the first match.

However, this means that we might get called more than once (typically
once for hid-generic, and once for hid-vendor-specific). So we store the
result of HID-BPF fixup in struct hid_device. Basically, this means that
->bpf_rdesc can replace ->dev_rdesc when it was used in the code.

In order to not grow struct hid_device, some fields are re-ordered. This
was the output of pahole for the first 128 bytes:
struct hid_device {
__u8 *                     dev_rdesc;            /*     0     8 */
unsigned int               dev_rsize;            /*     8     4 */

/* XXX 4 bytes hole, try to pack */

__u8 *                     rdesc;                /*    16     8 */
unsigned int               rsize;                /*    24     4 */

/* XXX 4 bytes hole, try to pack */

struct hid_collection *    collection;           /*    32     8 */
unsigned int               collection_size;      /*    40     4 */
unsigned int               maxcollection;        /*    44     4 */
unsigned int               maxapplication;       /*    48     4 */
__u16                      bus;                  /*    52     2 */
__u16                      group;                /*    54     2 */
__u32                      vendor;               /*    56     4 */
__u32                      product;              /*    60     4 */
/* --- cacheline 1 boundary (64 bytes) --- */
__u32                      version;              /*    64     4 */
enum hid_type              type;                 /*    68     4 */
unsigned int               country;              /*    72     4 */

/* XXX 4 bytes hole, try to pack */

struct hid_report_enum     report_enum[3];       /*    80  6216 */

Basically, we got three holes of 4 bytes. We can reorder things a little
and makes those 3 holes a continuous 12 bytes hole, which can be replaced
by the new pointer and the new unsigned int we need.

In terms of code allocation, when not using HID-BPF, we are back to kernel
v6.2 in hid_open_report(). These multiple kmemdup() calls will be fixed
in a later commit.

Link: https://patch.msgid.link/20241001-hid-bpf-hid-generic-v3-1-2ef1019468df@kernel.org
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
drivers/hid/bpf/hid_bpf_dispatch.c
drivers/hid/hid-core.c
include/linux/hid.h
include/linux/hid_bpf.h