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