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 | |