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 }; 15 16 __u64 callback_check = 52; 17 __u64 callback2_check = 52; 18 19 SEC("?fmod_ret/hid_bpf_device_event") 20 int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx) 21 { 22 __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */); 23 24 if (!rw_data) 25 return 0; /* EPERM check */ 26 27 callback_check = rw_data[1]; 28 29 rw_data[2] = rw_data[1] + 5; 30 31 return hid_ctx->size; 32 } 33 34 SEC("?fmod_ret/hid_bpf_device_event") 35 int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx) 36 { 37 __u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */); 38 39 if (!rw_data) 40 return 0; /* EPERM check */ 41 42 rw_data[0] = 2; 43 44 return 9; 45 } 46 47 SEC("syscall") 48 int attach_prog(struct attach_prog_args *ctx) 49 { 50 ctx->retval = hid_bpf_attach_prog(ctx->hid, 51 ctx->prog_fd, 52 0); 53 return 0; 54 } 55 56 struct hid_hw_request_syscall_args { 57 /* data needs to come at offset 0 so we can use it in calls */ 58 __u8 data[10]; 59 unsigned int hid; 60 int retval; 61 size_t size; 62 enum hid_report_type type; 63 __u8 request_type; 64 }; 65 66 SEC("syscall") 67 int hid_user_raw_request(struct hid_hw_request_syscall_args *args) 68 { 69 struct hid_bpf_ctx *ctx; 70 const size_t size = args->size; 71 int i, ret = 0; 72 73 if (size > sizeof(args->data)) 74 return -7; /* -E2BIG */ 75 76 ctx = hid_bpf_allocate_context(args->hid); 77 if (!ctx) 78 return -1; /* EPERM check */ 79 80 ret = hid_bpf_hw_request(ctx, 81 args->data, 82 size, 83 args->type, 84 args->request_type); 85 args->retval = ret; 86 87 hid_bpf_release_context(ctx); 88 89 return 0; 90 } 91 92 static const __u8 rdesc[] = { 93 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 94 0x09, 0x32, /* USAGE (Z) */ 95 0x95, 0x01, /* REPORT_COUNT (1) */ 96 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 97 98 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ 99 0x19, 0x01, /* USAGE_MINIMUM (1) */ 100 0x29, 0x03, /* USAGE_MAXIMUM (3) */ 101 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 102 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 103 0x95, 0x03, /* REPORT_COUNT (3) */ 104 0x75, 0x01, /* REPORT_SIZE (1) */ 105 0x91, 0x02, /* Output (Data,Var,Abs) */ 106 0x95, 0x01, /* REPORT_COUNT (1) */ 107 0x75, 0x05, /* REPORT_SIZE (5) */ 108 0x91, 0x01, /* Output (Cnst,Var,Abs) */ 109 110 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ 111 0x19, 0x06, /* USAGE_MINIMUM (6) */ 112 0x29, 0x08, /* USAGE_MAXIMUM (8) */ 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 0xb1, 0x02, /* Feature (Data,Var,Abs) */ 118 0x95, 0x01, /* REPORT_COUNT (1) */ 119 0x75, 0x05, /* REPORT_SIZE (5) */ 120 0x91, 0x01, /* Output (Cnst,Var,Abs) */ 121 122 0xc0, /* END_COLLECTION */ 123 0xc0, /* END_COLLECTION */ 124 }; 125 126 SEC("?fmod_ret/hid_bpf_rdesc_fixup") 127 int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx) 128 { 129 __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */); 130 131 if (!data) 132 return 0; /* EPERM check */ 133 134 callback2_check = data[4]; 135 136 /* insert rdesc at offset 73 */ 137 __builtin_memcpy(&data[73], rdesc, sizeof(rdesc)); 138 139 /* Change Usage Vendor globally */ 140 data[4] = 0x42; 141 142 return sizeof(rdesc) + 73; 143 } 144