summaryrefslogtreecommitdiff
path: root/include/linux/hid_bpf.h
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2022-11-03 16:57:44 +0100
committerJiri Kosina <jkosina@suse.cz>2022-11-15 16:28:28 +0100
commitf5c27da4e3c8a2e42fb4f41a0c685debcb9af294 (patch)
treedca477e34c80d61362ddd2ebbfbe2a4f9dc6bc22 /include/linux/hid_bpf.h
parent25621bcc89762fe1329ae9c9dab75bc70ef1aee0 (diff)
HID: initial BPF implementation
Declare an entry point that can use fmod_ret BPF programs, and also an API to access and change the incoming data. A simpler implementation would consist in just calling hid_bpf_device_event() for any incoming event and let users deal with the fact that they will be called for any event of any device. The goal of HID-BPF is to partially replace drivers, so this situation can be problematic because we might have programs which will step on each other toes. For that, we add a new API hid_bpf_attach_prog() that can be called from a syscall and we manually deal with a jump table in hid-bpf. Whenever we add a program to the jump table (in other words, when we attach a program to a HID device), we keep the number of time we added this program in the jump table so we can release it whenever there are no other users. HID devices have an RCU protected list of available programs in the jump table, and those programs are called one after the other thanks to bpf_tail_call(). To achieve the detection of users losing their fds on the programs we attached, we add 2 tracing facilities on bpf_prog_release() (for when a fd is closed) and bpf_free_inode() (for when a pinned program gets unpinned). Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'include/linux/hid_bpf.h')
-rw-r--r--include/linux/hid_bpf.h117
1 files changed, 117 insertions, 0 deletions
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
new file mode 100644
index 000000000000..de3fb1c376d2
--- /dev/null
+++ b/include/linux/hid_bpf.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __HID_BPF_H
+#define __HID_BPF_H
+
+#include <linux/spinlock.h>
+#include <uapi/linux/hid.h>
+
+struct hid_device;
+
+/*
+ * The following is the user facing HID BPF API.
+ *
+ * Extra care should be taken when editing this part, as
+ * it might break existing out of the tree bpf programs.
+ */
+
+/**
+ * struct hid_bpf_ctx - User accessible data for all HID programs
+ *
+ * ``data`` is not directly accessible from the context. We need to issue
+ * a call to ``hid_bpf_get_data()`` in order to get a pointer to that field.
+ *
+ * All of these fields are currently read-only.
+ *
+ * @index: program index in the jump table. No special meaning (a smaller index
+ * doesn't mean the program will be executed before another program with
+ * a bigger index).
+ * @hid: the ``struct hid_device`` representing the device itself
+ * @report_type: used for ``hid_bpf_device_event()``
+ * @size: Valid data in the data field.
+ *
+ * Programs can get the available valid size in data by fetching this field.
+ */
+struct hid_bpf_ctx {
+ __u32 index;
+ const struct hid_device *hid;
+ enum hid_report_type report_type;
+ __s32 size;
+};
+
+/**
+ * enum hid_bpf_attach_flags - flags used when attaching a HIF-BPF program
+ *
+ * @HID_BPF_FLAG_NONE: no specific flag is used, the kernel choses where to
+ * insert the program
+ * @HID_BPF_FLAG_INSERT_HEAD: insert the given program before any other program
+ * currently attached to the device. This doesn't
+ * guarantee that this program will always be first
+ * @HID_BPF_FLAG_MAX: sentinel value, not to be used by the callers
+ */
+enum hid_bpf_attach_flags {
+ HID_BPF_FLAG_NONE = 0,
+ HID_BPF_FLAG_INSERT_HEAD = _BITUL(0),
+ HID_BPF_FLAG_MAX,
+};
+
+/* Following functions are tracepoints that BPF programs can attach to */
+int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
+
+/* Following functions are kfunc that we export to BPF programs */
+/* only available in tracing */
+__u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz);
+
+/* only available in syscall */
+int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags);
+
+/*
+ * Below is HID internal
+ */
+
+/* internal function to call eBPF programs, not to be used by anybody */
+int __hid_bpf_tail_call(struct hid_bpf_ctx *ctx);
+
+#define HID_BPF_MAX_PROGS_PER_DEV 64
+#define HID_BPF_FLAG_MASK (((HID_BPF_FLAG_MAX - 1) << 1) - 1)
+
+/* types of HID programs to attach to */
+enum hid_bpf_prog_type {
+ HID_BPF_PROG_TYPE_UNDEF = -1,
+ HID_BPF_PROG_TYPE_DEVICE_EVENT, /* an event is emitted from the device */
+ HID_BPF_PROG_TYPE_MAX,
+};
+
+struct hid_bpf_ops {
+ struct module *owner;
+ struct bus_type *bus_type;
+};
+
+extern struct hid_bpf_ops *hid_bpf_ops;
+
+struct hid_bpf_prog_list {
+ u16 prog_idx[HID_BPF_MAX_PROGS_PER_DEV];
+ u8 prog_cnt;
+};
+
+/* stored in each device */
+struct hid_bpf {
+ struct hid_bpf_prog_list __rcu *progs[HID_BPF_PROG_TYPE_MAX]; /* attached BPF progs */
+ bool destroyed; /* prevents the assignment of any progs */
+
+ spinlock_t progs_lock; /* protects RCU update of progs */
+};
+
+#ifdef CONFIG_HID_BPF
+int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
+ u32 size, int interrupt);
+void hid_bpf_destroy_device(struct hid_device *hid);
+void hid_bpf_device_init(struct hid_device *hid);
+#else /* CONFIG_HID_BPF */
+static inline int dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
+ u8 *data, u32 size, int interrupt) { return 0; }
+static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
+static inline void hid_bpf_device_init(struct hid_device *hid) {}
+#endif /* CONFIG_HID_BPF */
+
+#endif /* __HID_BPF_H */