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