1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Facebook */
3 
4 #include <linux/bpf.h>
5 #include <stdint.h>
6 #include <bpf/bpf_helpers.h>
7 #include <bpf/bpf_core_read.h>
8 
9 char _license[] SEC("license") = "GPL";
10 
11 /* fields of exactly the same size */
12 struct test_struct___samesize {
13 	void *ptr;
14 	unsigned long long val1;
15 	unsigned int val2;
16 	unsigned short val3;
17 	unsigned char val4;
18 } __attribute((preserve_access_index));
19 
20 /* unsigned fields that have to be downsized by libbpf */
21 struct test_struct___downsize {
22 	void *ptr;
23 	unsigned long val1;
24 	unsigned long val2;
25 	unsigned long val3;
26 	unsigned long val4;
27 	/* total sz: 40 */
28 } __attribute__((preserve_access_index));
29 
30 /* fields with signed integers of wrong size, should be rejected */
31 struct test_struct___signed {
32 	void *ptr;
33 	long val1;
34 	long val2;
35 	long val3;
36 	long val4;
37 } __attribute((preserve_access_index));
38 
39 /* real layout and sizes according to test's (32-bit) BTF */
40 struct test_struct___real {
41 	unsigned int ptr; /* can't use `void *`, it is always 8 byte in BPF target */
42 	unsigned int val2;
43 	unsigned long long val1;
44 	unsigned short val3;
45 	unsigned char val4;
46 	unsigned char _pad;
47 	/* total sz: 20 */
48 };
49 
50 struct test_struct___real input = {
51 	.ptr = 0x01020304,
52 	.val1 = 0x1020304050607080,
53 	.val2 = 0x0a0b0c0d,
54 	.val3 = 0xfeed,
55 	.val4 = 0xb9,
56 	._pad = 0xff, /* make sure no accidental zeros are present */
57 };
58 
59 unsigned long long ptr_samesized = 0;
60 unsigned long long val1_samesized = 0;
61 unsigned long long val2_samesized = 0;
62 unsigned long long val3_samesized = 0;
63 unsigned long long val4_samesized = 0;
64 struct test_struct___real output_samesized = {};
65 
66 unsigned long long ptr_downsized = 0;
67 unsigned long long val1_downsized = 0;
68 unsigned long long val2_downsized = 0;
69 unsigned long long val3_downsized = 0;
70 unsigned long long val4_downsized = 0;
71 struct test_struct___real output_downsized = {};
72 
73 unsigned long long ptr_probed = 0;
74 unsigned long long val1_probed = 0;
75 unsigned long long val2_probed = 0;
76 unsigned long long val3_probed = 0;
77 unsigned long long val4_probed = 0;
78 
79 unsigned long long ptr_signed = 0;
80 unsigned long long val1_signed = 0;
81 unsigned long long val2_signed = 0;
82 unsigned long long val3_signed = 0;
83 unsigned long long val4_signed = 0;
84 struct test_struct___real output_signed = {};
85 
86 SEC("raw_tp/sys_exit")
87 int handle_samesize(void *ctx)
88 {
89 	struct test_struct___samesize *in = (void *)&input;
90 	struct test_struct___samesize *out = (void *)&output_samesized;
91 
92 	ptr_samesized = (unsigned long long)in->ptr;
93 	val1_samesized = in->val1;
94 	val2_samesized = in->val2;
95 	val3_samesized = in->val3;
96 	val4_samesized = in->val4;
97 
98 	out->ptr = in->ptr;
99 	out->val1 = in->val1;
100 	out->val2 = in->val2;
101 	out->val3 = in->val3;
102 	out->val4 = in->val4;
103 
104 	return 0;
105 }
106 
107 SEC("raw_tp/sys_exit")
108 int handle_downsize(void *ctx)
109 {
110 	struct test_struct___downsize *in = (void *)&input;
111 	struct test_struct___downsize *out = (void *)&output_downsized;
112 
113 	ptr_downsized = (unsigned long long)in->ptr;
114 	val1_downsized = in->val1;
115 	val2_downsized = in->val2;
116 	val3_downsized = in->val3;
117 	val4_downsized = in->val4;
118 
119 	out->ptr = in->ptr;
120 	out->val1 = in->val1;
121 	out->val2 = in->val2;
122 	out->val3 = in->val3;
123 	out->val4 = in->val4;
124 
125 	return 0;
126 }
127 
128 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
129 #define bpf_core_read_int bpf_core_read
130 #else
131 #define bpf_core_read_int(dst, sz, src) ({ \
132 	/* Prevent "subtraction from stack pointer prohibited" */ \
133 	volatile long __off = sizeof(*dst) - (sz); \
134 	bpf_core_read((char *)(dst) + __off, sz, src); \
135 })
136 #endif
137 
138 SEC("raw_tp/sys_enter")
139 int handle_probed(void *ctx)
140 {
141 	struct test_struct___downsize *in = (void *)&input;
142 	__u64 tmp;
143 
144 	tmp = 0;
145 	bpf_core_read_int(&tmp, bpf_core_field_size(in->ptr), &in->ptr);
146 	ptr_probed = tmp;
147 
148 	tmp = 0;
149 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val1), &in->val1);
150 	val1_probed = tmp;
151 
152 	tmp = 0;
153 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val2), &in->val2);
154 	val2_probed = tmp;
155 
156 	tmp = 0;
157 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val3), &in->val3);
158 	val3_probed = tmp;
159 
160 	tmp = 0;
161 	bpf_core_read_int(&tmp, bpf_core_field_size(in->val4), &in->val4);
162 	val4_probed = tmp;
163 
164 	return 0;
165 }
166 
167 SEC("raw_tp/sys_enter")
168 int handle_signed(void *ctx)
169 {
170 	struct test_struct___signed *in = (void *)&input;
171 	struct test_struct___signed *out = (void *)&output_signed;
172 
173 	val2_signed = in->val2;
174 	val3_signed = in->val3;
175 	val4_signed = in->val4;
176 
177 	out->val2= in->val2;
178 	out->val3= in->val3;
179 	out->val4= in->val4;
180 
181 	return 0;
182 }
183