[PATCH bpf-next v2 07/28] bpf/hid: add a new attach type to change the report descriptor

Benjamin Tissoires
2022-03-04T17:31:56Z

The report descriptor is the dictionary of the HID protocol specific
to the given device.
Changing it is a common habit in the HID world, and making that feature
accessible from eBPF allows to fix devices without having to install a
new kernel.

However, the report descriptor is supposed to be static on a device.
To be able to change it, we need to reconnect the device at the HID
level.
So whenever the report descriptor program type is attached or detached,
we call on a hook on HID to notify it that there is something to be
done.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

changes in v2:
- split the series by bpf/libbpf/hid/selftests and samples
- unsigned long -> __u16 in uapi/linux/bpf_hid.h
---
include/linux/bpf-hid.h | 4 ++++
include/uapi/linux/bpf.h | 1 +
include/uapi/linux/bpf_hid.h | 1 +
kernel/bpf/hid.c | 5 +++++
kernel/bpf/syscall.c | 2 ++
tools/include/uapi/linux/bpf.h | 1 +
6 files changed, 14 insertions(+)

diff --git a/include/linux/bpf-hid.h b/include/linux/bpf-hid.h
index 3cda78051b5f..0c5000b28b20 100644
--- a/include/linux/bpf-hid.h
+++ b/include/linux/bpf-hid.h
@@ -15,6 +15,7 @@ struct hid_device;
enum bpf_hid_attach_type {
BPF_HID_ATTACH_INVALID = -1,
BPF_HID_ATTACH_DEVICE_EVENT = 0,
+ BPF_HID_ATTACH_RDESC_FIXUP,
MAX_BPF_HID_ATTACH_TYPE
};

@@ -32,6 +33,8 @@ to_bpf_hid_attach_type(enum bpf_attach_type attach_type)
switch (attach_type) {
case BPF_HID_DEVICE_EVENT:
return BPF_HID_ATTACH_DEVICE_EVENT;
+ case BPF_HID_RDESC_FIXUP:
+ return BPF_HID_ATTACH_RDESC_FIXUP;
default:
return BPF_HID_ATTACH_INVALID;
}
@@ -88,6 +91,7 @@ static inline bool bpf_hid_link_empty(struct bpf_hid *bpf,
struct bpf_hid_hooks {
struct hid_device *(*hdev_from_fd)(int fd);
int (*link_attach)(struct hid_device *hdev, enum bpf_hid_attach_type type);
+ void (*link_attached)(struct hid_device *hdev, enum bpf_hid_attach_type type);
void (*array_detached)(struct hid_device *hdev, enum bpf_hid_attach_type type);
};

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 5978b92cacd3..a7a8d9cfcf24 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -999,6 +999,7 @@ enum bpf_attach_type {
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
BPF_PERF_EVENT,
BPF_HID_DEVICE_EVENT,
+ BPF_HID_RDESC_FIXUP,
__MAX_BPF_ATTACH_TYPE
};

diff --git a/include/uapi/linux/bpf_hid.h b/include/uapi/linux/bpf_hid.h
index 975ca5bd526f..634f17c0b1cb 100644
--- a/include/uapi/linux/bpf_hid.h
+++ b/include/uapi/linux/bpf_hid.h
@@ -24,6 +24,7 @@ struct hid_device;
enum hid_bpf_event {
HID_BPF_UNDEF = 0,
HID_BPF_DEVICE_EVENT, /* when attach type is BPF_HID_DEVICE_EVENT */
+ HID_BPF_RDESC_FIXUP, /* ................... BPF_HID_RDESC_FIXUP */
};

struct hid_bpf_ctx {
diff --git a/kernel/bpf/hid.c b/kernel/bpf/hid.c
index db7f75a0a812..37500313e270 100644
--- a/kernel/bpf/hid.c
+++ b/kernel/bpf/hid.c
@@ -315,6 +315,8 @@ static int bpf_hid_max_progs(enum bpf_hid_attach_type type)
switch (type) {
case BPF_HID_ATTACH_DEVICE_EVENT:
return 64;
+ case BPF_HID_ATTACH_RDESC_FIXUP:
+ return 1;
default:
return 0;
}
@@ -355,6 +357,9 @@ static int bpf_hid_link_attach(struct hid_device *hdev, struct bpf_link *link,
lockdep_is_held(&bpf_hid_mutex));
bpf_prog_array_free(run_array);

+ if (hid_hooks.link_attached)
+ hid_hooks.link_attached(hdev, type);
+
out_unlock:
mutex_unlock(&bpf_hid_mutex);
return err;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index a94e78ec3211..7428a1a512c6 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3203,6 +3203,7 @@ attach_type_to_prog_type(enum bpf_attach_type attach_type)
case BPF_XDP:
return BPF_PROG_TYPE_XDP;
case BPF_HID_DEVICE_EVENT:
+ case BPF_HID_RDESC_FIXUP:
return BPF_PROG_TYPE_HID;
default:
return BPF_PROG_TYPE_UNSPEC;
@@ -3348,6 +3349,7 @@ static int bpf_prog_query(const union bpf_attr *attr,
case BPF_SK_SKB_VERDICT:
return sock_map_bpf_prog_query(attr, uattr);
case BPF_HID_DEVICE_EVENT:
+ case BPF_HID_RDESC_FIXUP:
return bpf_hid_prog_query(attr, uattr);
default:
return -EINVAL;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 5978b92cacd3..a7a8d9cfcf24 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -999,6 +999,7 @@ enum bpf_attach_type {
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
BPF_PERF_EVENT,
BPF_HID_DEVICE_EVENT,
+ BPF_HID_RDESC_FIXUP,
__MAX_BPF_ATTACH_TYPE
};

--
2.35.1