1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022 Red hat */ 3 #include "vmlinux.h" 4 #include <bpf/bpf_helpers.h> 5 #include <bpf/bpf_tracing.h> 6 #include "hid_bpf_helpers.h" 7 8 char _license[] SEC("license") = "GPL"; 9 10 struct attach_prog_args { 11 int prog_fd; 12 unsigned int hid; 13 int retval; 14 int insert_head; 15 }; 16 17 __u64 callback_check = 52; 18 __u64 callback2_check = 52; 19 20 SEC("?fmod_ret/hid_bpf_device_event") 21 int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx) 22 { 23 __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */); 24 25 if (!rw_data) 26 return 0; /* EPERM check */ 27 28 callback_check = rw_data[1]; 29 30 rw_data[2] = rw_data[1] + 5; 31 32 return hid_ctx->size; 33 } 34 35 SEC("?fmod_ret/hid_bpf_device_event") 36 int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx) 37 { 38 __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); 39 40 if (!rw_data) 41 return 0; /* EPERM check */ 42 43 rw_data[3] = rw_data[2] + 5; 44 45 return hid_ctx->size; 46 } 47 48 SEC("?fmod_ret/hid_bpf_device_event") 49 int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx) 50 { 51 __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */); 52 53 if (!rw_data) 54 return 0; /* EPERM check */ 55 56 rw_data[0] = 2; 57 58 return 9; 59 } 60 61 SEC("syscall") 62 int attach_prog(struct attach_prog_args *ctx) 63 { 64 ctx->retval = hid_bpf_attach_prog(ctx->hid, 65 ctx->prog_fd, 66 ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD : 67 HID_BPF_FLAG_NONE); 68 return 0; 69 } 70 71 struct hid_hw_request_syscall_args { 72 /* data needs to come at offset 0 so we can use it in calls */ 73 __u8 data[10]; 74 unsigned int hid; 75 int retval; 76 size_t size; 77 enum hid_report_type type; 78 __u8 request_type; 79 }; 80 81 SEC("syscall") 82 int hid_user_raw_request(struct hid_hw_request_syscall_args *args) 83 { 84 struct hid_bpf_ctx *ctx; 85 const size_t size = args->size; 86 int i, ret = 0; 87 88 if (size > sizeof(args->data)) 89 return -7; /* -E2BIG */ 90 91 ctx = hid_bpf_allocate_context(args->hid); 92 if (!ctx) 93 return -1; /* EPERM check */ 94 95 ret = hid_bpf_hw_request(ctx, 96 args->data, 97 size, 98 args->type, 99 args->request_type); 100 args->retval = ret; 101 102 hid_bpf_release_context(ctx); 103 104 return 0; 105 } 106 107 static const __u8 rdesc[] = { 108 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 109 0x09, 0x32, /* USAGE (Z) */ 110 0x95, 0x01, /* REPORT_COUNT (1) */ 111 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 112 113 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ 114 0x19, 0x01, /* USAGE_MINIMUM (1) */ 115 0x29, 0x03, /* USAGE_MAXIMUM (3) */ 116 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 117 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 118 0x95, 0x03, /* REPORT_COUNT (3) */ 119 0x75, 0x01, /* REPORT_SIZE (1) */ 120 0x91, 0x02, /* Output (Data,Var,Abs) */ 121 0x95, 0x01, /* REPORT_COUNT (1) */ 122 0x75, 0x05, /* REPORT_SIZE (5) */ 123 0x91, 0x01, /* Output (Cnst,Var,Abs) */ 124 125 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ 126 0x19, 0x06, /* USAGE_MINIMUM (6) */ 127 0x29, 0x08, /* USAGE_MAXIMUM (8) */ 128 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 129 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 130 0x95, 0x03, /* REPORT_COUNT (3) */ 131 0x75, 0x01, /* REPORT_SIZE (1) */ 132 0xb1, 0x02, /* Feature (Data,Var,Abs) */ 133 0x95, 0x01, /* REPORT_COUNT (1) */ 134 0x75, 0x05, /* REPORT_SIZE (5) */ 135 0x91, 0x01, /* Output (Cnst,Var,Abs) */ 136 137 0xc0, /* END_COLLECTION */ 138 0xc0, /* END_COLLECTION */ 139 }; 140 141 SEC("?fmod_ret/hid_bpf_rdesc_fixup") 142 int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx) 143 { 144 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */); 145 146 if (!data) 147 return 0; /* EPERM check */ 148 149 callback2_check = data[4]; 150 151 /* insert rdesc at offset 73 */ 152 __builtin_memcpy(&data[73], rdesc, sizeof(rdesc)); 153 154 /* Change Usage Vendor globally */ 155 data[4] = 0x42; 156 157 return sizeof(rdesc) + 73; 158 } 159 160 SEC("?fmod_ret/hid_bpf_device_event") 161 int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx) 162 { 163 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); 164 165 if (!data) 166 return 0; /* EPERM check */ 167 168 /* we need to be run first */ 169 if (data[2] || data[3]) 170 return -1; 171 172 data[1] = 1; 173 174 return 0; 175 } 176 177 SEC("?fmod_ret/hid_bpf_device_event") 178 int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx) 179 { 180 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); 181 182 if (!data) 183 return 0; /* EPERM check */ 184 185 /* after insert0 and before insert2 */ 186 if (!data[1] || data[3]) 187 return -1; 188 189 data[2] = 2; 190 191 return 0; 192 } 193 194 SEC("?fmod_ret/hid_bpf_device_event") 195 int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx) 196 { 197 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */); 198 199 if (!data) 200 return 0; /* EPERM check */ 201 202 /* at the end */ 203 if (!data[1] || !data[2]) 204 return -1; 205 206 data[3] = 3; 207 208 return 0; 209 } 210