hid-bpf.rst 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. .. SPDX-License-Identifier: GPL-2.0
  2. =======
  3. HID-BPF
  4. =======
  5. HID is a standard protocol for input devices but some devices may require
  6. custom tweaks, traditionally done with a kernel driver fix. Using the eBPF
  7. capabilities instead speeds up development and adds new capabilities to the
  8. existing HID interfaces.
  9. .. contents::
  10. :local:
  11. :depth: 2
  12. When (and why) to use HID-BPF
  13. =============================
  14. There are several use cases when using HID-BPF is better
  15. than standard kernel driver fix:
  16. Dead zone of a joystick
  17. -----------------------
  18. Assuming you have a joystick that is getting older, it is common to see it
  19. wobbling around its neutral point. This is usually filtered at the application
  20. level by adding a *dead zone* for this specific axis.
  21. With HID-BPF, we can apply this filtering in the kernel directly so userspace
  22. does not get woken up when nothing else is happening on the input controller.
  23. Of course, given that this dead zone is specific to an individual device, we
  24. can not create a generic fix for all of the same joysticks. Adding a custom
  25. kernel API for this (e.g. by adding a sysfs entry) does not guarantee this new
  26. kernel API will be broadly adopted and maintained.
  27. HID-BPF allows the userspace program to load the program itself, ensuring we
  28. only load the custom API when we have a user.
  29. Simple fixup of report descriptor
  30. ---------------------------------
  31. In the HID tree, half of the drivers only fix one key or one byte
  32. in the report descriptor. These fixes all require a kernel patch and the
  33. subsequent shepherding into a release, a long and painful process for users.
  34. We can reduce this burden by providing an eBPF program instead. Once such a
  35. program has been verified by the user, we can embed the source code into the
  36. kernel tree and ship the eBPF program and load it directly instead of loading
  37. a specific kernel module for it.
  38. Note: distribution of eBPF programs and their inclusion in the kernel is not
  39. yet fully implemented
  40. Add a new feature that requires a new kernel API
  41. ------------------------------------------------
  42. An example for such a feature are the Universal Stylus Interface (USI) pens.
  43. Basically, USI pens require a new kernel API because there are new
  44. channels of communication that our HID and input stack do not support.
  45. Instead of using hidraw or creating new sysfs entries or ioctls, we can rely
  46. on eBPF to have the kernel API controlled by the consumer and to not
  47. impact the performances by waking up userspace every time there is an
  48. event.
  49. Morph a device into something else and control that from userspace
  50. ------------------------------------------------------------------
  51. The kernel has a relatively static mapping of HID items to evdev bits.
  52. It cannot decide to dynamically transform a given device into something else
  53. as it does not have the required context and any such transformation cannot be
  54. undone (or even discovered) by userspace.
  55. However, some devices are useless with that static way of defining devices. For
  56. example, the Microsoft Surface Dial is a pushbutton with haptic feedback that
  57. is barely usable as of today.
  58. With eBPF, userspace can morph that device into a mouse, and convert the dial
  59. events into wheel events. Also, the userspace program can set/unset the haptic
  60. feedback depending on the context. For example, if a menu is visible on the
  61. screen we likely need to have a haptic click every 15 degrees. But when
  62. scrolling in a web page the user experience is better when the device emits
  63. events at the highest resolution.
  64. Firewall
  65. --------
  66. What if we want to prevent other users to access a specific feature of a
  67. device? (think a possibly broken firmware update entry point)
  68. With eBPF, we can intercept any HID command emitted to the device and
  69. validate it or not.
  70. This also allows to sync the state between the userspace and the
  71. kernel/bpf program because we can intercept any incoming command.
  72. Tracing
  73. -------
  74. The last usage is tracing events and all the fun we can do we BPF to summarize
  75. and analyze events.
  76. Right now, tracing relies on hidraw. It works well except for a couple
  77. of issues:
  78. 1. if the driver doesn't export a hidraw node, we can't trace anything
  79. (eBPF will be a "god-mode" there, so this may raise some eyebrows)
  80. 2. hidraw doesn't catch other processes' requests to the device, which
  81. means that we have cases where we need to add printks to the kernel
  82. to understand what is happening.
  83. High-level view of HID-BPF
  84. ==========================
  85. The main idea behind HID-BPF is that it works at an array of bytes level.
  86. Thus, all of the parsing of the HID report and the HID report descriptor
  87. must be implemented in the userspace component that loads the eBPF
  88. program.
  89. For example, in the dead zone joystick from above, knowing which fields
  90. in the data stream needs to be set to ``0`` needs to be computed by userspace.
  91. A corollary of this is that HID-BPF doesn't know about the other subsystems
  92. available in the kernel. *You can not directly emit input event through the
  93. input API from eBPF*.
  94. When a BPF program needs to emit input events, it needs to talk with the HID
  95. protocol, and rely on the HID kernel processing to translate the HID data into
  96. input events.
  97. In-tree HID-BPF programs and ``udev-hid-bpf``
  98. =============================================
  99. Official device fixes are shipped in the kernel tree as source in the
  100. ``drivers/hid/bpf/progs`` directory. This allows to add selftests to them in
  101. ``tools/testing/selftests/hid``.
  102. However, the compilation of these objects is not part of a regular kernel compilation
  103. given that they need an external tool to be loaded. This tool is currently
  104. `udev-hid-bpf <https://libevdev.pages.freedesktop.org/udev-hid-bpf/index.html>`_.
  105. For convenience, that external repository duplicates the files from here in
  106. ``drivers/hid/bpf/progs`` into its own ``src/bpf/stable`` directory. This allows
  107. distributions to not have to pull the entire kernel source tree to ship and package
  108. those HID-BPF fixes. ``udev-hid-bpf`` also has capabilities of handling multiple
  109. objects files depending on the kernel the user is running.
  110. Available types of programs
  111. ===========================
  112. HID-BPF is built "on top" of BPF, meaning that we use bpf struct_ops method to
  113. declare our programs.
  114. HID-BPF has the following attachment types available:
  115. 1. event processing/filtering with ``SEC("struct_ops/hid_device_event")`` in libbpf
  116. 2. actions coming from userspace with ``SEC("syscall")`` in libbpf
  117. 3. change of the report descriptor with ``SEC("struct_ops/hid_rdesc_fixup")`` or
  118. ``SEC("struct_ops.s/hid_rdesc_fixup")`` in libbpf
  119. A ``hid_device_event`` is calling a BPF program when an event is received from
  120. the device. Thus we are in IRQ context and can act on the data or notify userspace.
  121. And given that we are in IRQ context, we can not talk back to the device.
  122. A ``syscall`` means that userspace called the syscall ``BPF_PROG_RUN`` facility.
  123. This time, we can do any operations allowed by HID-BPF, and talking to the device is
  124. allowed.
  125. Last, ``hid_rdesc_fixup`` is different from the others as there can be only one
  126. BPF program of this type. This is called on ``probe`` from the driver and allows to
  127. change the report descriptor from the BPF program. Once a ``hid_rdesc_fixup``
  128. program has been loaded, it is not possible to overwrite it unless the program which
  129. inserted it allows us by pinning the program and closing all of its fds pointing to it.
  130. Note that ``hid_rdesc_fixup`` can be declared as sleepable (``SEC("struct_ops.s/hid_rdesc_fixup")``).
  131. Developer API:
  132. ==============
  133. Available ``struct_ops`` for HID-BPF:
  134. -------------------------------------
  135. .. kernel-doc:: include/linux/hid_bpf.h
  136. :identifiers: hid_bpf_ops
  137. User API data structures available in programs:
  138. -----------------------------------------------
  139. .. kernel-doc:: include/linux/hid_bpf.h
  140. :identifiers: hid_bpf_ctx
  141. Available API that can be used in all HID-BPF struct_ops programs:
  142. ------------------------------------------------------------------
  143. .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
  144. :identifiers: hid_bpf_get_data
  145. Available API that can be used in syscall HID-BPF programs or in sleepable HID-BPF struct_ops programs:
  146. -------------------------------------------------------------------------------------------------------
  147. .. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
  148. :identifiers: hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_try_input_report hid_bpf_allocate_context hid_bpf_release_context
  149. General overview of a HID-BPF program
  150. =====================================
  151. Accessing the data attached to the context
  152. ------------------------------------------
  153. The ``struct hid_bpf_ctx`` doesn't export the ``data`` fields directly and to access
  154. it, a bpf program needs to first call :c:func:`hid_bpf_get_data`.
  155. ``offset`` can be any integer, but ``size`` needs to be constant, known at compile
  156. time.
  157. This allows the following:
  158. 1. for a given device, if we know that the report length will always be of a certain value,
  159. we can request the ``data`` pointer to point at the full report length.
  160. The kernel will ensure we are using a correct size and offset and eBPF will ensure
  161. the code will not attempt to read or write outside of the boundaries::
  162. __u8 *data = hid_bpf_get_data(ctx, 0 /* offset */, 256 /* size */);
  163. if (!data)
  164. return 0; /* ensure data is correct, now the verifier knows we
  165. * have 256 bytes available */
  166. bpf_printk("hello world: %02x %02x %02x", data[0], data[128], data[255]);
  167. 2. if the report length is variable, but we know the value of ``X`` is always a 16-bit
  168. integer, we can then have a pointer to that value only::
  169. __u16 *x = hid_bpf_get_data(ctx, offset, sizeof(*x));
  170. if (!x)
  171. return 0; /* something went wrong */
  172. *x += 1; /* increment X by one */
  173. Effect of a HID-BPF program
  174. ---------------------------
  175. For all HID-BPF attachment types except for :c:func:`hid_rdesc_fixup`, several eBPF
  176. programs can be attached to the same device. If a HID-BPF struct_ops has a
  177. :c:func:`hid_rdesc_fixup` while another is already attached to the device, the
  178. kernel will return `-EINVAL` when attaching the struct_ops.
  179. Unless ``BPF_F_BEFORE`` is added to the flags while attaching the program, the new
  180. program is appended at the end of the list.
  181. ``BPF_F_BEFORE`` will insert the new program at the beginning of the list which is
  182. useful for e.g. tracing where we need to get the unprocessed events from the device.
  183. Note that if there are multiple programs using the ``BPF_F_BEFORE`` flag,
  184. only the most recently loaded one is actually the first in the list.
  185. ``SEC("struct_ops/hid_device_event")``
  186. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  187. Whenever a matching event is raised, the eBPF programs are called one after the other
  188. and are working on the same data buffer.
  189. If a program changes the data associated with the context, the next one will see
  190. the modified data but it will have *no* idea of what the original data was.
  191. Once all the programs are run and return ``0`` or a positive value, the rest of the
  192. HID stack will work on the modified data, with the ``size`` field of the last hid_bpf_ctx
  193. being the new size of the input stream of data.
  194. A BPF program returning a negative error discards the event, i.e. this event will not be
  195. processed by the HID stack. Clients (hidraw, input, LEDs) will **not** see this event.
  196. ``SEC("syscall")``
  197. ~~~~~~~~~~~~~~~~~~
  198. ``syscall`` are not attached to a given device. To tell which device we are working
  199. with, userspace needs to refer to the device by its unique system id (the last 4 numbers
  200. in the sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``).
  201. To retrieve a context associated with the device, the program must call
  202. hid_bpf_allocate_context() and must release it with hid_bpf_release_context()
  203. before returning.
  204. Once the context is retrieved, one can also request a pointer to kernel memory with
  205. hid_bpf_get_data(). This memory is big enough to support all input/output/feature
  206. reports of the given device.
  207. ``SEC("struct_ops/hid_rdesc_fixup")``
  208. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  209. The ``hid_rdesc_fixup`` program works in a similar manner to ``.report_fixup``
  210. of ``struct hid_driver``.
  211. When the device is probed, the kernel sets the data buffer of the context with the
  212. content of the report descriptor. The memory associated with that buffer is
  213. ``HID_MAX_DESCRIPTOR_SIZE`` (currently 4kB).
  214. The eBPF program can modify the data buffer at-will and the kernel uses the
  215. modified content and size as the report descriptor.
  216. Whenever a struct_ops containing a ``SEC("struct_ops/hid_rdesc_fixup")`` program
  217. is attached (if no program was attached before), the kernel immediately disconnects
  218. the HID device and does a reprobe.
  219. In the same way, when this struct_ops is detached, the kernel issues a disconnect
  220. on the device.
  221. There is no ``detach`` facility in HID-BPF. Detaching a program happens when
  222. all the user space file descriptors pointing at a HID-BPF struct_ops link are closed.
  223. Thus, if we need to replace a report descriptor fixup, some cooperation is
  224. required from the owner of the original report descriptor fixup.
  225. The previous owner will likely pin the struct_ops link in the bpffs, and we can then
  226. replace it through normal bpf operations.
  227. Attaching a bpf program to a device
  228. ===================================
  229. We now use standard struct_ops attachment through ``bpf_map__attach_struct_ops()``.
  230. But given that we need to attach a struct_ops to a dedicated HID device, the caller
  231. must set ``hid_id`` in the struct_ops map before loading the program in the kernel.
  232. ``hid_id`` is the unique system ID of the HID device (the last 4 numbers in the
  233. sysfs path: ``/sys/bus/hid/devices/xxxx:yyyy:zzzz:0000``)
  234. One can also set ``flags``, which is of type ``enum hid_bpf_attach_flags``.
  235. We can not rely on hidraw to bind a BPF program to a HID device. hidraw is an
  236. artefact of the processing of the HID device, and is not stable. Some drivers
  237. even disable it, so that removes the tracing capabilities on those devices
  238. (where it is interesting to get the non-hidraw traces).
  239. On the other hand, the ``hid_id`` is stable for the entire life of the HID device,
  240. even if we change its report descriptor.
  241. Given that hidraw is not stable when the device disconnects/reconnects, we recommend
  242. accessing the current report descriptor of the device through the sysfs.
  243. This is available at ``/sys/bus/hid/devices/BUS:VID:PID.000N/report_descriptor`` as a
  244. binary stream.
  245. Parsing the report descriptor is the responsibility of the BPF programmer or the userspace
  246. component that loads the eBPF program.
  247. An (almost) complete example of a BPF enhanced HID device
  248. =========================================================
  249. *Foreword: for most parts, this could be implemented as a kernel driver*
  250. Let's imagine we have a new tablet device that has some haptic capabilities
  251. to simulate the surface the user is scratching on. This device would also have
  252. a specific 3 positions switch to toggle between *pencil on paper*, *cray on a wall*
  253. and *brush on a painting canvas*. To make things even better, we can control the
  254. physical position of the switch through a feature report.
  255. And of course, the switch is relying on some userspace component to control the
  256. haptic feature of the device itself.
  257. Filtering events
  258. ----------------
  259. The first step consists in filtering events from the device. Given that the switch
  260. position is actually reported in the flow of the pen events, using hidraw to implement
  261. that filtering would mean that we wake up userspace for every single event.
  262. This is OK for libinput, but having an external library that is just interested in
  263. one byte in the report is less than ideal.
  264. For that, we can create a basic skeleton for our BPF program::
  265. #include "vmlinux.h"
  266. #include <bpf/bpf_helpers.h>
  267. #include <bpf/bpf_tracing.h>
  268. /* HID programs need to be GPL */
  269. char _license[] SEC("license") = "GPL";
  270. /* HID-BPF kfunc API definitions */
  271. extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
  272. unsigned int offset,
  273. const size_t __sz) __ksym;
  274. struct {
  275. __uint(type, BPF_MAP_TYPE_RINGBUF);
  276. __uint(max_entries, 4096 * 64);
  277. } ringbuf SEC(".maps");
  278. __u8 current_value = 0;
  279. SEC("struct_ops/hid_device_event")
  280. int BPF_PROG(filter_switch, struct hid_bpf_ctx *hid_ctx)
  281. {
  282. __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 192 /* size */);
  283. __u8 *buf;
  284. if (!data)
  285. return 0; /* EPERM check */
  286. if (current_value != data[152]) {
  287. buf = bpf_ringbuf_reserve(&ringbuf, 1, 0);
  288. if (!buf)
  289. return 0;
  290. *buf = data[152];
  291. bpf_ringbuf_commit(buf, 0);
  292. current_value = data[152];
  293. }
  294. return 0;
  295. }
  296. SEC(".struct_ops.link")
  297. struct hid_bpf_ops haptic_tablet = {
  298. .hid_device_event = (void *)filter_switch,
  299. };
  300. To attach ``haptic_tablet``, userspace needs to set ``hid_id`` first::
  301. static int attach_filter(struct hid *hid_skel, int hid_id)
  302. {
  303. int err, link_fd;
  304. hid_skel->struct_ops.haptic_tablet->hid_id = hid_id;
  305. err = hid__load(skel);
  306. if (err)
  307. return err;
  308. link_fd = bpf_map__attach_struct_ops(hid_skel->maps.haptic_tablet);
  309. if (!link_fd) {
  310. fprintf(stderr, "can not attach HID-BPF program: %m\n");
  311. return -1;
  312. }
  313. return link_fd; /* the fd of the created bpf_link */
  314. }
  315. Our userspace program can now listen to notifications on the ring buffer, and
  316. is awaken only when the value changes.
  317. When the userspace program doesn't need to listen to events anymore, it can just
  318. close the returned bpf link from :c:func:`attach_filter`, which will tell the kernel to
  319. detach the program from the HID device.
  320. Of course, in other use cases, the userspace program can also pin the fd to the
  321. BPF filesystem through a call to :c:func:`bpf_obj_pin`, as with any bpf_link.
  322. Controlling the device
  323. ----------------------
  324. To be able to change the haptic feedback from the tablet, the userspace program
  325. needs to emit a feature report on the device itself.
  326. Instead of using hidraw for that, we can create a ``SEC("syscall")`` program
  327. that talks to the device::
  328. /* some more HID-BPF kfunc API definitions */
  329. extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
  330. extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
  331. extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
  332. __u8* data,
  333. size_t len,
  334. enum hid_report_type type,
  335. enum hid_class_request reqtype) __ksym;
  336. struct hid_send_haptics_args {
  337. /* data needs to come at offset 0 so we can do a memcpy into it */
  338. __u8 data[10];
  339. unsigned int hid;
  340. };
  341. SEC("syscall")
  342. int send_haptic(struct hid_send_haptics_args *args)
  343. {
  344. struct hid_bpf_ctx *ctx;
  345. int ret = 0;
  346. ctx = hid_bpf_allocate_context(args->hid);
  347. if (!ctx)
  348. return 0; /* EPERM check */
  349. ret = hid_bpf_hw_request(ctx,
  350. args->data,
  351. 10,
  352. HID_FEATURE_REPORT,
  353. HID_REQ_SET_REPORT);
  354. hid_bpf_release_context(ctx);
  355. return ret;
  356. }
  357. And then userspace needs to call that program directly::
  358. static int set_haptic(struct hid *hid_skel, int hid_id, __u8 haptic_value)
  359. {
  360. int err, prog_fd;
  361. int ret = -1;
  362. struct hid_send_haptics_args args = {
  363. .hid = hid_id,
  364. };
  365. DECLARE_LIBBPF_OPTS(bpf_test_run_opts, tattrs,
  366. .ctx_in = &args,
  367. .ctx_size_in = sizeof(args),
  368. );
  369. args.data[0] = 0x02; /* report ID of the feature on our device */
  370. args.data[1] = haptic_value;
  371. prog_fd = bpf_program__fd(hid_skel->progs.set_haptic);
  372. err = bpf_prog_test_run_opts(prog_fd, &tattrs);
  373. return err;
  374. }
  375. Now our userspace program is aware of the haptic state and can control it. The
  376. program could make this state further available to other userspace programs
  377. (e.g. via a DBus API).
  378. The interesting bit here is that we did not created a new kernel API for this.
  379. Which means that if there is a bug in our implementation, we can change the
  380. interface with the kernel at-will, because the userspace application is
  381. responsible for its own usage.