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