1888d83b9SAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0
2888d83b9SAndrii Nakryiko /* Copyright (c) 2020 Facebook */
3888d83b9SAndrii Nakryiko 
4888d83b9SAndrii Nakryiko #include <linux/bpf.h>
5888d83b9SAndrii Nakryiko #include <stdint.h>
6888d83b9SAndrii Nakryiko #include <bpf/bpf_helpers.h>
7888d83b9SAndrii Nakryiko #include <bpf/bpf_core_read.h>
8888d83b9SAndrii Nakryiko 
9888d83b9SAndrii Nakryiko char _license[] SEC("license") = "GPL";
10888d83b9SAndrii Nakryiko 
11888d83b9SAndrii Nakryiko /* fields of exactly the same size */
12888d83b9SAndrii Nakryiko struct test_struct___samesize {
13888d83b9SAndrii Nakryiko 	void *ptr;
14888d83b9SAndrii Nakryiko 	unsigned long long val1;
15888d83b9SAndrii Nakryiko 	unsigned int val2;
16888d83b9SAndrii Nakryiko 	unsigned short val3;
17888d83b9SAndrii Nakryiko 	unsigned char val4;
18888d83b9SAndrii Nakryiko } __attribute((preserve_access_index));
19888d83b9SAndrii Nakryiko 
20888d83b9SAndrii Nakryiko /* unsigned fields that have to be downsized by libbpf */
21888d83b9SAndrii Nakryiko struct test_struct___downsize {
22888d83b9SAndrii Nakryiko 	void *ptr;
23888d83b9SAndrii Nakryiko 	unsigned long val1;
24888d83b9SAndrii Nakryiko 	unsigned long val2;
25888d83b9SAndrii Nakryiko 	unsigned long val3;
26888d83b9SAndrii Nakryiko 	unsigned long val4;
27888d83b9SAndrii Nakryiko 	/* total sz: 40 */
28888d83b9SAndrii Nakryiko } __attribute__((preserve_access_index));
29888d83b9SAndrii Nakryiko 
30888d83b9SAndrii Nakryiko /* fields with signed integers of wrong size, should be rejected */
31888d83b9SAndrii Nakryiko struct test_struct___signed {
32888d83b9SAndrii Nakryiko 	void *ptr;
33888d83b9SAndrii Nakryiko 	long val1;
34888d83b9SAndrii Nakryiko 	long val2;
35888d83b9SAndrii Nakryiko 	long val3;
36888d83b9SAndrii Nakryiko 	long val4;
37888d83b9SAndrii Nakryiko } __attribute((preserve_access_index));
38888d83b9SAndrii Nakryiko 
39888d83b9SAndrii Nakryiko /* real layout and sizes according to test's (32-bit) BTF */
40888d83b9SAndrii Nakryiko struct test_struct___real {
41888d83b9SAndrii Nakryiko 	unsigned int ptr; /* can't use `void *`, it is always 8 byte in BPF target */
42888d83b9SAndrii Nakryiko 	unsigned int val2;
43888d83b9SAndrii Nakryiko 	unsigned long long val1;
44888d83b9SAndrii Nakryiko 	unsigned short val3;
45888d83b9SAndrii Nakryiko 	unsigned char val4;
46888d83b9SAndrii Nakryiko 	unsigned char _pad;
47888d83b9SAndrii Nakryiko 	/* total sz: 20 */
48888d83b9SAndrii Nakryiko };
49888d83b9SAndrii Nakryiko 
50888d83b9SAndrii Nakryiko struct test_struct___real input = {
51888d83b9SAndrii Nakryiko 	.ptr = 0x01020304,
52888d83b9SAndrii Nakryiko 	.val1 = 0x1020304050607080,
53888d83b9SAndrii Nakryiko 	.val2 = 0x0a0b0c0d,
54888d83b9SAndrii Nakryiko 	.val3 = 0xfeed,
55888d83b9SAndrii Nakryiko 	.val4 = 0xb9,
56888d83b9SAndrii Nakryiko 	._pad = 0xff, /* make sure no accidental zeros are present */
57888d83b9SAndrii Nakryiko };
58888d83b9SAndrii Nakryiko 
59888d83b9SAndrii Nakryiko unsigned long long ptr_samesized = 0;
60888d83b9SAndrii Nakryiko unsigned long long val1_samesized = 0;
61888d83b9SAndrii Nakryiko unsigned long long val2_samesized = 0;
62888d83b9SAndrii Nakryiko unsigned long long val3_samesized = 0;
63888d83b9SAndrii Nakryiko unsigned long long val4_samesized = 0;
64888d83b9SAndrii Nakryiko struct test_struct___real output_samesized = {};
65888d83b9SAndrii Nakryiko 
66888d83b9SAndrii Nakryiko unsigned long long ptr_downsized = 0;
67888d83b9SAndrii Nakryiko unsigned long long val1_downsized = 0;
68888d83b9SAndrii Nakryiko unsigned long long val2_downsized = 0;
69888d83b9SAndrii Nakryiko unsigned long long val3_downsized = 0;
70888d83b9SAndrii Nakryiko unsigned long long val4_downsized = 0;
71888d83b9SAndrii Nakryiko struct test_struct___real output_downsized = {};
72888d83b9SAndrii Nakryiko 
73888d83b9SAndrii Nakryiko unsigned long long ptr_probed = 0;
74888d83b9SAndrii Nakryiko unsigned long long val1_probed = 0;
75888d83b9SAndrii Nakryiko unsigned long long val2_probed = 0;
76888d83b9SAndrii Nakryiko unsigned long long val3_probed = 0;
77888d83b9SAndrii Nakryiko unsigned long long val4_probed = 0;
78888d83b9SAndrii Nakryiko 
79888d83b9SAndrii Nakryiko unsigned long long ptr_signed = 0;
80888d83b9SAndrii Nakryiko unsigned long long val1_signed = 0;
81888d83b9SAndrii Nakryiko unsigned long long val2_signed = 0;
82888d83b9SAndrii Nakryiko unsigned long long val3_signed = 0;
83888d83b9SAndrii Nakryiko unsigned long long val4_signed = 0;
84888d83b9SAndrii Nakryiko struct test_struct___real output_signed = {};
85888d83b9SAndrii Nakryiko 
86888d83b9SAndrii Nakryiko SEC("raw_tp/sys_exit")
handle_samesize(void * ctx)87888d83b9SAndrii Nakryiko int handle_samesize(void *ctx)
88888d83b9SAndrii Nakryiko {
89888d83b9SAndrii Nakryiko 	struct test_struct___samesize *in = (void *)&input;
90888d83b9SAndrii Nakryiko 	struct test_struct___samesize *out = (void *)&output_samesized;
91888d83b9SAndrii Nakryiko 
92888d83b9SAndrii Nakryiko 	ptr_samesized = (unsigned long long)in->ptr;
93888d83b9SAndrii Nakryiko 	val1_samesized = in->val1;
94888d83b9SAndrii Nakryiko 	val2_samesized = in->val2;
95888d83b9SAndrii Nakryiko 	val3_samesized = in->val3;
96888d83b9SAndrii Nakryiko 	val4_samesized = in->val4;
97888d83b9SAndrii Nakryiko 
98888d83b9SAndrii Nakryiko 	out->ptr = in->ptr;
99888d83b9SAndrii Nakryiko 	out->val1 = in->val1;
100888d83b9SAndrii Nakryiko 	out->val2 = in->val2;
101888d83b9SAndrii Nakryiko 	out->val3 = in->val3;
102888d83b9SAndrii Nakryiko 	out->val4 = in->val4;
103888d83b9SAndrii Nakryiko 
104888d83b9SAndrii Nakryiko 	return 0;
105888d83b9SAndrii Nakryiko }
106888d83b9SAndrii Nakryiko 
107888d83b9SAndrii Nakryiko SEC("raw_tp/sys_exit")
handle_downsize(void * ctx)108888d83b9SAndrii Nakryiko int handle_downsize(void *ctx)
109888d83b9SAndrii Nakryiko {
110888d83b9SAndrii Nakryiko 	struct test_struct___downsize *in = (void *)&input;
111888d83b9SAndrii Nakryiko 	struct test_struct___downsize *out = (void *)&output_downsized;
112888d83b9SAndrii Nakryiko 
113888d83b9SAndrii Nakryiko 	ptr_downsized = (unsigned long long)in->ptr;
114888d83b9SAndrii Nakryiko 	val1_downsized = in->val1;
115888d83b9SAndrii Nakryiko 	val2_downsized = in->val2;
116888d83b9SAndrii Nakryiko 	val3_downsized = in->val3;
117888d83b9SAndrii Nakryiko 	val4_downsized = in->val4;
118888d83b9SAndrii Nakryiko 
119888d83b9SAndrii Nakryiko 	out->ptr = in->ptr;
120888d83b9SAndrii Nakryiko 	out->val1 = in->val1;
121888d83b9SAndrii Nakryiko 	out->val2 = in->val2;
122888d83b9SAndrii Nakryiko 	out->val3 = in->val3;
123888d83b9SAndrii Nakryiko 	out->val4 = in->val4;
124888d83b9SAndrii Nakryiko 
125888d83b9SAndrii Nakryiko 	return 0;
126888d83b9SAndrii Nakryiko }
127888d83b9SAndrii Nakryiko 
128*d164dd9aSIlya Leoshkevich #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
129*d164dd9aSIlya Leoshkevich #define bpf_core_read_int bpf_core_read
130*d164dd9aSIlya Leoshkevich #else
131*d164dd9aSIlya Leoshkevich #define bpf_core_read_int(dst, sz, src) ({ \
132*d164dd9aSIlya Leoshkevich 	/* Prevent "subtraction from stack pointer prohibited" */ \
133*d164dd9aSIlya Leoshkevich 	volatile long __off = sizeof(*dst) - (sz); \
134*d164dd9aSIlya Leoshkevich 	bpf_core_read((char *)(dst) + __off, sz, src); \
135*d164dd9aSIlya Leoshkevich })
136*d164dd9aSIlya Leoshkevich #endif
137*d164dd9aSIlya Leoshkevich 
138888d83b9SAndrii Nakryiko SEC("raw_tp/sys_enter")
handle_probed(void * ctx)139888d83b9SAndrii Nakryiko int handle_probed(void *ctx)
140888d83b9SAndrii Nakryiko {
141888d83b9SAndrii Nakryiko 	struct test_struct___downsize *in = (void *)&input;
142888d83b9SAndrii Nakryiko 	__u64 tmp;
143888d83b9SAndrii Nakryiko 
144888d83b9SAndrii Nakryiko 	tmp = 0;
145*d164dd9aSIlya Leoshkevich 	bpf_core_read_int(&tmp, bpf_core_field_size(in->ptr), &in->ptr);
146888d83b9SAndrii Nakryiko 	ptr_probed = tmp;
147888d83b9SAndrii Nakryiko 
148888d83b9SAndrii Nakryiko 	tmp = 0;
149*d164dd9aSIlya Leoshkevich 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val1), &in->val1);
150888d83b9SAndrii Nakryiko 	val1_probed = tmp;
151888d83b9SAndrii Nakryiko 
152888d83b9SAndrii Nakryiko 	tmp = 0;
153*d164dd9aSIlya Leoshkevich 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val2), &in->val2);
154888d83b9SAndrii Nakryiko 	val2_probed = tmp;
155888d83b9SAndrii Nakryiko 
156888d83b9SAndrii Nakryiko 	tmp = 0;
157*d164dd9aSIlya Leoshkevich 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val3), &in->val3);
158888d83b9SAndrii Nakryiko 	val3_probed = tmp;
159888d83b9SAndrii Nakryiko 
160888d83b9SAndrii Nakryiko 	tmp = 0;
161*d164dd9aSIlya Leoshkevich 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val4), &in->val4);
162888d83b9SAndrii Nakryiko 	val4_probed = tmp;
163888d83b9SAndrii Nakryiko 
164888d83b9SAndrii Nakryiko 	return 0;
165888d83b9SAndrii Nakryiko }
166888d83b9SAndrii Nakryiko 
167888d83b9SAndrii Nakryiko SEC("raw_tp/sys_enter")
handle_signed(void * ctx)168888d83b9SAndrii Nakryiko int handle_signed(void *ctx)
169888d83b9SAndrii Nakryiko {
170888d83b9SAndrii Nakryiko 	struct test_struct___signed *in = (void *)&input;
171888d83b9SAndrii Nakryiko 	struct test_struct___signed *out = (void *)&output_signed;
172888d83b9SAndrii Nakryiko 
173888d83b9SAndrii Nakryiko 	val2_signed = in->val2;
174888d83b9SAndrii Nakryiko 	val3_signed = in->val3;
175888d83b9SAndrii Nakryiko 	val4_signed = in->val4;
176888d83b9SAndrii Nakryiko 
177888d83b9SAndrii Nakryiko 	out->val2= in->val2;
178888d83b9SAndrii Nakryiko 	out->val3= in->val3;
179888d83b9SAndrii Nakryiko 	out->val4= in->val4;
180888d83b9SAndrii Nakryiko 
181888d83b9SAndrii Nakryiko 	return 0;
182888d83b9SAndrii Nakryiko }
183