1dbb60c8aSBenjamin Tissoires // SPDX-License-Identifier: GPL-2.0
2dbb60c8aSBenjamin Tissoires /* Copyright (c) 2022 Red hat */
3dbb60c8aSBenjamin Tissoires #include "vmlinux.h"
4dbb60c8aSBenjamin Tissoires #include <bpf/bpf_helpers.h>
5dbb60c8aSBenjamin Tissoires #include <bpf/bpf_tracing.h>
6dbb60c8aSBenjamin Tissoires #include "hid_bpf_helpers.h"
7dbb60c8aSBenjamin Tissoires 
8dbb60c8aSBenjamin Tissoires char _license[] SEC("license") = "GPL";
9dbb60c8aSBenjamin Tissoires 
10dbb60c8aSBenjamin Tissoires struct attach_prog_args {
11dbb60c8aSBenjamin Tissoires 	int prog_fd;
12dbb60c8aSBenjamin Tissoires 	unsigned int hid;
13dbb60c8aSBenjamin Tissoires 	int retval;
1480e189f2SBenjamin Tissoires 	int insert_head;
15dbb60c8aSBenjamin Tissoires };
16dbb60c8aSBenjamin Tissoires 
17dbb60c8aSBenjamin Tissoires __u64 callback_check = 52;
18dbb60c8aSBenjamin Tissoires __u64 callback2_check = 52;
19dbb60c8aSBenjamin Tissoires 
20dbb60c8aSBenjamin Tissoires SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_first_event,struct hid_bpf_ctx * hid_ctx)21dbb60c8aSBenjamin Tissoires int BPF_PROG(hid_first_event, struct hid_bpf_ctx *hid_ctx)
22dbb60c8aSBenjamin Tissoires {
23dbb60c8aSBenjamin Tissoires 	__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
24dbb60c8aSBenjamin Tissoires 
25dbb60c8aSBenjamin Tissoires 	if (!rw_data)
26dbb60c8aSBenjamin Tissoires 		return 0; /* EPERM check */
27dbb60c8aSBenjamin Tissoires 
28dbb60c8aSBenjamin Tissoires 	callback_check = rw_data[1];
29dbb60c8aSBenjamin Tissoires 
30dbb60c8aSBenjamin Tissoires 	rw_data[2] = rw_data[1] + 5;
31dbb60c8aSBenjamin Tissoires 
320330f725SBenjamin Tissoires 	return hid_ctx->size;
330330f725SBenjamin Tissoires }
340330f725SBenjamin Tissoires 
350330f725SBenjamin Tissoires SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_second_event,struct hid_bpf_ctx * hid_ctx)36*cea6c4d9SBenjamin Tissoires int BPF_PROG(hid_second_event, struct hid_bpf_ctx *hid_ctx)
37*cea6c4d9SBenjamin Tissoires {
38*cea6c4d9SBenjamin Tissoires 	__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
39*cea6c4d9SBenjamin Tissoires 
40*cea6c4d9SBenjamin Tissoires 	if (!rw_data)
41*cea6c4d9SBenjamin Tissoires 		return 0; /* EPERM check */
42*cea6c4d9SBenjamin Tissoires 
43*cea6c4d9SBenjamin Tissoires 	rw_data[3] = rw_data[2] + 5;
44*cea6c4d9SBenjamin Tissoires 
45*cea6c4d9SBenjamin Tissoires 	return hid_ctx->size;
46*cea6c4d9SBenjamin Tissoires }
47*cea6c4d9SBenjamin Tissoires 
48*cea6c4d9SBenjamin Tissoires SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_change_report_id,struct hid_bpf_ctx * hid_ctx)490330f725SBenjamin Tissoires int BPF_PROG(hid_change_report_id, struct hid_bpf_ctx *hid_ctx)
500330f725SBenjamin Tissoires {
510330f725SBenjamin Tissoires 	__u8 *rw_data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 3 /* size */);
520330f725SBenjamin Tissoires 
530330f725SBenjamin Tissoires 	if (!rw_data)
540330f725SBenjamin Tissoires 		return 0; /* EPERM check */
550330f725SBenjamin Tissoires 
560330f725SBenjamin Tissoires 	rw_data[0] = 2;
570330f725SBenjamin Tissoires 
580330f725SBenjamin Tissoires 	return 9;
59dbb60c8aSBenjamin Tissoires }
60dbb60c8aSBenjamin Tissoires 
61dbb60c8aSBenjamin Tissoires SEC("syscall")
attach_prog(struct attach_prog_args * ctx)62dbb60c8aSBenjamin Tissoires int attach_prog(struct attach_prog_args *ctx)
63dbb60c8aSBenjamin Tissoires {
64dbb60c8aSBenjamin Tissoires 	ctx->retval = hid_bpf_attach_prog(ctx->hid,
65dbb60c8aSBenjamin Tissoires 					  ctx->prog_fd,
6680e189f2SBenjamin Tissoires 					  ctx->insert_head ? HID_BPF_FLAG_INSERT_HEAD :
6780e189f2SBenjamin Tissoires 							     HID_BPF_FLAG_NONE);
68dbb60c8aSBenjamin Tissoires 	return 0;
69dbb60c8aSBenjamin Tissoires }
704f7153cfSBenjamin Tissoires 
714f7153cfSBenjamin Tissoires struct hid_hw_request_syscall_args {
724f7153cfSBenjamin Tissoires 	/* data needs to come at offset 0 so we can use it in calls */
734f7153cfSBenjamin Tissoires 	__u8 data[10];
744f7153cfSBenjamin Tissoires 	unsigned int hid;
754f7153cfSBenjamin Tissoires 	int retval;
764f7153cfSBenjamin Tissoires 	size_t size;
774f7153cfSBenjamin Tissoires 	enum hid_report_type type;
784f7153cfSBenjamin Tissoires 	__u8 request_type;
794f7153cfSBenjamin Tissoires };
804f7153cfSBenjamin Tissoires 
814f7153cfSBenjamin Tissoires SEC("syscall")
hid_user_raw_request(struct hid_hw_request_syscall_args * args)824f7153cfSBenjamin Tissoires int hid_user_raw_request(struct hid_hw_request_syscall_args *args)
834f7153cfSBenjamin Tissoires {
844f7153cfSBenjamin Tissoires 	struct hid_bpf_ctx *ctx;
854f7153cfSBenjamin Tissoires 	const size_t size = args->size;
864f7153cfSBenjamin Tissoires 	int i, ret = 0;
874f7153cfSBenjamin Tissoires 
884f7153cfSBenjamin Tissoires 	if (size > sizeof(args->data))
894f7153cfSBenjamin Tissoires 		return -7; /* -E2BIG */
904f7153cfSBenjamin Tissoires 
914f7153cfSBenjamin Tissoires 	ctx = hid_bpf_allocate_context(args->hid);
924f7153cfSBenjamin Tissoires 	if (!ctx)
934f7153cfSBenjamin Tissoires 		return -1; /* EPERM check */
944f7153cfSBenjamin Tissoires 
954f7153cfSBenjamin Tissoires 	ret = hid_bpf_hw_request(ctx,
964f7153cfSBenjamin Tissoires 				 args->data,
974f7153cfSBenjamin Tissoires 				 size,
984f7153cfSBenjamin Tissoires 				 args->type,
994f7153cfSBenjamin Tissoires 				 args->request_type);
1004f7153cfSBenjamin Tissoires 	args->retval = ret;
1014f7153cfSBenjamin Tissoires 
1024f7153cfSBenjamin Tissoires 	hid_bpf_release_context(ctx);
1034f7153cfSBenjamin Tissoires 
1044f7153cfSBenjamin Tissoires 	return 0;
1054f7153cfSBenjamin Tissoires }
106e8445737SBenjamin Tissoires 
107e8445737SBenjamin Tissoires static const __u8 rdesc[] = {
108e8445737SBenjamin Tissoires 	0x05, 0x01,				/* USAGE_PAGE (Generic Desktop) */
109e8445737SBenjamin Tissoires 	0x09, 0x32,				/* USAGE (Z) */
110e8445737SBenjamin Tissoires 	0x95, 0x01,				/* REPORT_COUNT (1) */
111e8445737SBenjamin Tissoires 	0x81, 0x06,				/* INPUT (Data,Var,Rel) */
112e8445737SBenjamin Tissoires 
113e8445737SBenjamin Tissoires 	0x06, 0x00, 0xff,			/* Usage Page (Vendor Defined Page 1) */
114e8445737SBenjamin Tissoires 	0x19, 0x01,				/* USAGE_MINIMUM (1) */
115e8445737SBenjamin Tissoires 	0x29, 0x03,				/* USAGE_MAXIMUM (3) */
116e8445737SBenjamin Tissoires 	0x15, 0x00,				/* LOGICAL_MINIMUM (0) */
117e8445737SBenjamin Tissoires 	0x25, 0x01,				/* LOGICAL_MAXIMUM (1) */
118e8445737SBenjamin Tissoires 	0x95, 0x03,				/* REPORT_COUNT (3) */
119e8445737SBenjamin Tissoires 	0x75, 0x01,				/* REPORT_SIZE (1) */
120e8445737SBenjamin Tissoires 	0x91, 0x02,				/* Output (Data,Var,Abs) */
121e8445737SBenjamin Tissoires 	0x95, 0x01,				/* REPORT_COUNT (1) */
122e8445737SBenjamin Tissoires 	0x75, 0x05,				/* REPORT_SIZE (5) */
123e8445737SBenjamin Tissoires 	0x91, 0x01,				/* Output (Cnst,Var,Abs) */
124e8445737SBenjamin Tissoires 
125e8445737SBenjamin Tissoires 	0x06, 0x00, 0xff,			/* Usage Page (Vendor Defined Page 1) */
126e8445737SBenjamin Tissoires 	0x19, 0x06,				/* USAGE_MINIMUM (6) */
127e8445737SBenjamin Tissoires 	0x29, 0x08,				/* USAGE_MAXIMUM (8) */
128e8445737SBenjamin Tissoires 	0x15, 0x00,				/* LOGICAL_MINIMUM (0) */
129e8445737SBenjamin Tissoires 	0x25, 0x01,				/* LOGICAL_MAXIMUM (1) */
130e8445737SBenjamin Tissoires 	0x95, 0x03,				/* REPORT_COUNT (3) */
131e8445737SBenjamin Tissoires 	0x75, 0x01,				/* REPORT_SIZE (1) */
132e8445737SBenjamin Tissoires 	0xb1, 0x02,				/* Feature (Data,Var,Abs) */
133e8445737SBenjamin Tissoires 	0x95, 0x01,				/* REPORT_COUNT (1) */
134e8445737SBenjamin Tissoires 	0x75, 0x05,				/* REPORT_SIZE (5) */
135e8445737SBenjamin Tissoires 	0x91, 0x01,				/* Output (Cnst,Var,Abs) */
136e8445737SBenjamin Tissoires 
137e8445737SBenjamin Tissoires 	0xc0,				/* END_COLLECTION */
138e8445737SBenjamin Tissoires 	0xc0,			/* END_COLLECTION */
139e8445737SBenjamin Tissoires };
140e8445737SBenjamin Tissoires 
141e8445737SBenjamin Tissoires SEC("?fmod_ret/hid_bpf_rdesc_fixup")
BPF_PROG(hid_rdesc_fixup,struct hid_bpf_ctx * hid_ctx)142e8445737SBenjamin Tissoires int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx)
143e8445737SBenjamin Tissoires {
144e8445737SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */);
145e8445737SBenjamin Tissoires 
146e8445737SBenjamin Tissoires 	if (!data)
147e8445737SBenjamin Tissoires 		return 0; /* EPERM check */
148e8445737SBenjamin Tissoires 
149e8445737SBenjamin Tissoires 	callback2_check = data[4];
150e8445737SBenjamin Tissoires 
151e8445737SBenjamin Tissoires 	/* insert rdesc at offset 73 */
152e8445737SBenjamin Tissoires 	__builtin_memcpy(&data[73], rdesc, sizeof(rdesc));
153e8445737SBenjamin Tissoires 
154e8445737SBenjamin Tissoires 	/* Change Usage Vendor globally */
155e8445737SBenjamin Tissoires 	data[4] = 0x42;
156e8445737SBenjamin Tissoires 
157e8445737SBenjamin Tissoires 	return sizeof(rdesc) + 73;
158e8445737SBenjamin Tissoires }
15980e189f2SBenjamin Tissoires 
16080e189f2SBenjamin Tissoires SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_test_insert1,struct hid_bpf_ctx * hid_ctx)16180e189f2SBenjamin Tissoires int BPF_PROG(hid_test_insert1, struct hid_bpf_ctx *hid_ctx)
16280e189f2SBenjamin Tissoires {
16380e189f2SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
16480e189f2SBenjamin Tissoires 
16580e189f2SBenjamin Tissoires 	if (!data)
16680e189f2SBenjamin Tissoires 		return 0; /* EPERM check */
16780e189f2SBenjamin Tissoires 
16880e189f2SBenjamin Tissoires 	/* we need to be run first */
16980e189f2SBenjamin Tissoires 	if (data[2] || data[3])
17080e189f2SBenjamin Tissoires 		return -1;
17180e189f2SBenjamin Tissoires 
17280e189f2SBenjamin Tissoires 	data[1] = 1;
17380e189f2SBenjamin Tissoires 
17480e189f2SBenjamin Tissoires 	return 0;
17580e189f2SBenjamin Tissoires }
17680e189f2SBenjamin Tissoires 
17780e189f2SBenjamin Tissoires SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_test_insert2,struct hid_bpf_ctx * hid_ctx)17880e189f2SBenjamin Tissoires int BPF_PROG(hid_test_insert2, struct hid_bpf_ctx *hid_ctx)
17980e189f2SBenjamin Tissoires {
18080e189f2SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
18180e189f2SBenjamin Tissoires 
18280e189f2SBenjamin Tissoires 	if (!data)
18380e189f2SBenjamin Tissoires 		return 0; /* EPERM check */
18480e189f2SBenjamin Tissoires 
18580e189f2SBenjamin Tissoires 	/* after insert0 and before insert2 */
18680e189f2SBenjamin Tissoires 	if (!data[1] || data[3])
18780e189f2SBenjamin Tissoires 		return -1;
18880e189f2SBenjamin Tissoires 
18980e189f2SBenjamin Tissoires 	data[2] = 2;
19080e189f2SBenjamin Tissoires 
19180e189f2SBenjamin Tissoires 	return 0;
19280e189f2SBenjamin Tissoires }
19380e189f2SBenjamin Tissoires 
19480e189f2SBenjamin Tissoires SEC("?fmod_ret/hid_bpf_device_event")
BPF_PROG(hid_test_insert3,struct hid_bpf_ctx * hid_ctx)19580e189f2SBenjamin Tissoires int BPF_PROG(hid_test_insert3, struct hid_bpf_ctx *hid_ctx)
19680e189f2SBenjamin Tissoires {
19780e189f2SBenjamin Tissoires 	__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4 /* size */);
19880e189f2SBenjamin Tissoires 
19980e189f2SBenjamin Tissoires 	if (!data)
20080e189f2SBenjamin Tissoires 		return 0; /* EPERM check */
20180e189f2SBenjamin Tissoires 
20280e189f2SBenjamin Tissoires 	/* at the end */
20380e189f2SBenjamin Tissoires 	if (!data[1] || !data[2])
20480e189f2SBenjamin Tissoires 		return -1;
20580e189f2SBenjamin Tissoires 
20680e189f2SBenjamin Tissoires 	data[3] = 3;
20780e189f2SBenjamin Tissoires 
20880e189f2SBenjamin Tissoires 	return 0;
20980e189f2SBenjamin Tissoires }
210