1// SPDX-License-Identifier: GPL-2.0 2/* Copyright (c) 2022 Red hat */ 3#include "hid_bpf_helpers.h" 4 5char _license[] SEC("license") = "GPL"; 6 7struct 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 17SEC("?fmod_ret/hid_bpf_device_event") 18int 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 32SEC("?fmod_ret/hid_bpf_device_event") 33int 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 45SEC("?fmod_ret/hid_bpf_device_event") 46int 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 58SEC("syscall") 59int 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 68struct 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 78SEC("syscall") 79int 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 104static 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 138SEC("?fmod_ret/hid_bpf_rdesc_fixup") 139int 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 157SEC("?fmod_ret/hid_bpf_device_event") 158int 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 174SEC("?fmod_ret/hid_bpf_device_event") 175int 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 191SEC("?fmod_ret/hid_bpf_device_event") 192int 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