xref: /linux/drivers/hid/bpf/hid_bpf_dispatch.c (revision dbb60c8a26daf388f183f599e1e96de5bb9f96e1)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 /*
4  *  HID-BPF support for Linux
5  *
6  *  Copyright (c) 2022 Benjamin Tissoires
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 #include <linux/bitops.h>
11 #include <linux/btf.h>
12 #include <linux/btf_ids.h>
13 #include <linux/filter.h>
14 #include <linux/hid.h>
15 #include <linux/hid_bpf.h>
16 #include <linux/init.h>
17 #include <linux/kfifo.h>
18 #include <linux/module.h>
19 #include <linux/workqueue.h>
20 #include "hid_bpf_dispatch.h"
21 #include "entrypoints/entrypoints.lskel.h"
22 
23 struct hid_bpf_ops *hid_bpf_ops;
24 EXPORT_SYMBOL(hid_bpf_ops);
25 
26 /**
27  * hid_bpf_device_event - Called whenever an event is coming in from the device
28  *
29  * @ctx: The HID-BPF context
30  *
31  * @return %0 on success and keep processing; a negative error code to interrupt
32  * the processing of this event
33  *
34  * Declare an %fmod_ret tracing bpf program to this function and attach this
35  * program through hid_bpf_attach_prog() to have this helper called for
36  * any incoming event from the device itself.
37  *
38  * The function is called while on IRQ context, so we can not sleep.
39  */
40 /* never used by the kernel but declared so we can load and attach a tracepoint */
41 __weak noinline int hid_bpf_device_event(struct hid_bpf_ctx *ctx)
42 {
43 	return 0;
44 }
45 ALLOW_ERROR_INJECTION(hid_bpf_device_event, ERRNO);
46 
47 int
48 dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
49 			      u32 size, int interrupt)
50 {
51 	struct hid_bpf_ctx_kern ctx_kern = {
52 		.ctx = {
53 			.hid = hdev,
54 			.report_type = type,
55 			.size = size,
56 		},
57 		.data = data,
58 	};
59 
60 	if (type >= HID_REPORT_TYPES)
61 		return -EINVAL;
62 
63 	return hid_bpf_prog_run(hdev, HID_BPF_PROG_TYPE_DEVICE_EVENT, &ctx_kern);
64 }
65 EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
66 
67 /**
68  * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
69  *
70  * @ctx: The HID-BPF context
71  * @offset: The offset within the memory
72  * @rdwr_buf_size: the const size of the buffer
73  *
74  * @returns %NULL on error, an %__u8 memory pointer on success
75  */
76 noinline __u8 *
77 hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
78 {
79 	struct hid_bpf_ctx_kern *ctx_kern;
80 
81 	if (!ctx)
82 		return NULL;
83 
84 	ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
85 
86 	if (rdwr_buf_size + offset > ctx->size)
87 		return NULL;
88 
89 	return ctx_kern->data + offset;
90 }
91 
92 /*
93  * The following set contains all functions we agree BPF programs
94  * can use.
95  */
96 BTF_SET8_START(hid_bpf_kfunc_ids)
97 BTF_ID_FLAGS(func, call_hid_bpf_prog_release)
98 BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
99 BTF_SET8_END(hid_bpf_kfunc_ids)
100 
101 static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
102 	.owner = THIS_MODULE,
103 	.set   = &hid_bpf_kfunc_ids,
104 };
105 
106 static int device_match_id(struct device *dev, const void *id)
107 {
108 	struct hid_device *hdev = to_hid_device(dev);
109 
110 	return hdev->id == *(int *)id;
111 }
112 
113 /**
114  * hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
115  *
116  * @hid_id: the system unique identifier of the HID device
117  * @prog_fd: an fd in the user process representing the program to attach
118  * @flags: any logical OR combination of &enum hid_bpf_attach_flags
119  *
120  * @returns %0 on success, an error code otherwise.
121  */
122 /* called from syscall */
123 noinline int
124 hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
125 {
126 	struct hid_device *hdev;
127 	struct device *dev;
128 	int prog_type = hid_bpf_get_prog_attach_type(prog_fd);
129 
130 	if (!hid_bpf_ops)
131 		return -EINVAL;
132 
133 	if (prog_type < 0)
134 		return prog_type;
135 
136 	if (prog_type >= HID_BPF_PROG_TYPE_MAX)
137 		return -EINVAL;
138 
139 	if ((flags & ~HID_BPF_FLAG_MASK))
140 		return -EINVAL;
141 
142 	dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
143 	if (!dev)
144 		return -EINVAL;
145 
146 	hdev = to_hid_device(dev);
147 
148 	return __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
149 }
150 
151 /* for syscall HID-BPF */
152 BTF_SET8_START(hid_bpf_syscall_kfunc_ids)
153 BTF_ID_FLAGS(func, hid_bpf_attach_prog)
154 BTF_SET8_END(hid_bpf_syscall_kfunc_ids)
155 
156 static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
157 	.owner = THIS_MODULE,
158 	.set   = &hid_bpf_syscall_kfunc_ids,
159 };
160 
161 void hid_bpf_destroy_device(struct hid_device *hdev)
162 {
163 	if (!hdev)
164 		return;
165 
166 	/* mark the device as destroyed in bpf so we don't reattach it */
167 	hdev->bpf.destroyed = true;
168 
169 	__hid_bpf_destroy_device(hdev);
170 }
171 EXPORT_SYMBOL_GPL(hid_bpf_destroy_device);
172 
173 void hid_bpf_device_init(struct hid_device *hdev)
174 {
175 	spin_lock_init(&hdev->bpf.progs_lock);
176 }
177 EXPORT_SYMBOL_GPL(hid_bpf_device_init);
178 
179 static int __init hid_bpf_init(void)
180 {
181 	int err;
182 
183 	/* Note: if we exit with an error any time here, we would entirely break HID, which
184 	 * is probably not something we want. So we log an error and return success.
185 	 *
186 	 * This is not a big deal: the syscall allowing to attach a BPF program to a HID device
187 	 * will not be available, so nobody will be able to use the functionality.
188 	 */
189 
190 	err = register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &hid_bpf_kfunc_set);
191 	if (err) {
192 		pr_warn("error while setting HID BPF tracing kfuncs: %d", err);
193 		return 0;
194 	}
195 
196 	err = hid_bpf_preload_skel();
197 	if (err) {
198 		pr_warn("error while preloading HID BPF dispatcher: %d", err);
199 		return 0;
200 	}
201 
202 	/* register syscalls after we are sure we can load our preloaded bpf program */
203 	err = register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &hid_bpf_syscall_kfunc_set);
204 	if (err) {
205 		pr_warn("error while setting HID BPF syscall kfuncs: %d", err);
206 		return 0;
207 	}
208 
209 	return 0;
210 }
211 
212 static void __exit hid_bpf_exit(void)
213 {
214 	/* HID depends on us, so if we hit that code, we are guaranteed that hid
215 	 * has been removed and thus we do not need to clear the HID devices
216 	 */
217 	hid_bpf_free_links_and_skel();
218 }
219 
220 late_initcall(hid_bpf_init);
221 module_exit(hid_bpf_exit);
222 MODULE_AUTHOR("Benjamin Tissoires");
223 MODULE_LICENSE("GPL");
224