1 /*-
2 * Copyright (c) 2013 Alexander Nasonov.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #define __BPF_PRIVATE
31 #include <bpfjit.h>
32
33 #include <stdbool.h>
34 #include <stdint.h>
35
36 #include "util.h"
37 #include "tests.h"
38
39 static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
40 static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
41 static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
42 static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
43 static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
44
45 static const bpf_copfunc_t copfuncs[] = {
46 &retA,
47 &retBL,
48 &retWL,
49 &retNF,
50 &setARG
51 };
52
53 static const bpf_ctx_t ctx = {
54 .copfuncs = copfuncs,
55 .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
56 .extwords = 0
57 };
58
59 static uint32_t
retA(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)60 retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
61 {
62
63 return A;
64 }
65
66 static uint32_t
retBL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)67 retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
68 {
69
70 return args->buflen;
71 }
72
73 static uint32_t
retWL(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)74 retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
75 {
76
77 return args->wirelen;
78 }
79
80 static uint32_t
retNF(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)81 retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
82 {
83
84 return bc->nfuncs;
85 }
86
87 /*
88 * COP function with a side effect.
89 */
90 static uint32_t
setARG(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)91 setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
92 {
93 bool *arg = (bool *)args->arg;
94 bool old = *arg;
95
96 *arg = true;
97 return old;
98 }
99
100 static void
test_copx_no_ctx(void)101 test_copx_no_ctx(void)
102 {
103 static struct bpf_insn insns[] = {
104 BPF_STMT(BPF_MISC+BPF_COPX, 0),
105 BPF_STMT(BPF_RET+BPF_K, 7)
106 };
107
108 bpfjit_func_t code;
109
110 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
111
112 //XXX CHECK(bpf_validate(insns, insn_count));
113
114 code = bpfjit_generate_code(NULL, insns, insn_count);
115 REQUIRE(code == NULL);
116 }
117
118 static void
test_copx_ret_A(void)119 test_copx_ret_A(void)
120 {
121 static struct bpf_insn insns[] = {
122 BPF_STMT(BPF_LD+BPF_IMM, 13),
123 //BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
124 BPF_STMT(BPF_MISC+BPF_COPX, 0),
125 BPF_STMT(BPF_RET+BPF_A, 0)
126 };
127
128 bpfjit_func_t code;
129 uint8_t pkt[1] = { 0 };
130 bpf_args_t args = { pkt, sizeof(pkt), sizeof(pkt) };
131
132 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
133
134 //CHECK(bpf_validate(insns, insn_count));
135
136 code = bpfjit_generate_code(&ctx, insns, insn_count);
137 REQUIRE(code != NULL);
138
139 CHECK(code(&ctx, &args) == 13);
140
141 bpfjit_free_code(code);
142 }
143
144 static void
test_copx_ret_buflen(void)145 test_copx_ret_buflen(void)
146 {
147 static struct bpf_insn insns[] = {
148 BPF_STMT(BPF_LD+BPF_IMM, 13),
149 BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
150 BPF_STMT(BPF_MISC+BPF_COPX, 0),
151 BPF_STMT(BPF_RET+BPF_A, 0)
152 };
153
154 bpfjit_func_t code;
155 uint8_t pkt[1] = { 0 };
156 bpf_args_t args = { pkt, sizeof(pkt), sizeof(pkt) };
157
158 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
159
160 //CHECK(bpf_validate(insns, insn_count));
161
162 code = bpfjit_generate_code(&ctx, insns, insn_count);
163 REQUIRE(code != NULL);
164
165 CHECK(code(&ctx, &args) == sizeof(pkt));
166
167 bpfjit_free_code(code);
168 }
169
170 static void
test_copx_ret_wirelen(void)171 test_copx_ret_wirelen(void)
172 {
173 static struct bpf_insn insns[] = {
174 BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
175 BPF_STMT(BPF_LD+BPF_IMM, 13),
176 BPF_STMT(BPF_MISC+BPF_COPX, 0),
177 BPF_STMT(BPF_RET+BPF_A, 0)
178 };
179
180 bpfjit_func_t code;
181 uint8_t pkt[1] = { 0 };
182 bpf_args_t args = { pkt, sizeof(pkt), sizeof(pkt) };
183
184 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
185
186 //CHECK(bpf_validate(insns, insn_count));
187
188 code = bpfjit_generate_code(&ctx, insns, insn_count);
189 REQUIRE(code != NULL);
190
191 CHECK(code(&ctx, &args) == sizeof(pkt));
192
193 bpfjit_free_code(code);
194 }
195
196 static void
test_copx_ret_nfuncs(void)197 test_copx_ret_nfuncs(void)
198 {
199 static struct bpf_insn insns[] = {
200 BPF_STMT(BPF_LD+BPF_IMM, 13),
201 BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
202 BPF_STMT(BPF_MISC+BPF_COPX, 0),
203 BPF_STMT(BPF_RET+BPF_A, 0)
204 };
205
206 bpfjit_func_t code;
207 uint8_t pkt[1] = { 0 };
208 bpf_args_t args = { pkt, sizeof(pkt), sizeof(pkt) };
209
210 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
211
212 //CHECK(bpf_validate(insns, insn_count));
213
214 code = bpfjit_generate_code(&ctx, insns, insn_count);
215 REQUIRE(code != NULL);
216
217 CHECK(code(&ctx, &args) == ctx.nfuncs);
218
219 bpfjit_free_code(code);
220 }
221
222 /*
223 * Check that safe_length optimization doesn't skip BPF_COP call.
224 */
225 static void
test_copx_mixed_with_ld(void)226 test_copx_mixed_with_ld(void)
227 {
228 static struct bpf_insn insns[] = {
229 BPF_STMT(BPF_LD+BPF_IMM, 13),
230 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
231 BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
232 BPF_STMT(BPF_MISC+BPF_COPX, 0),
233 BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
234 BPF_STMT(BPF_RET+BPF_A, 0)
235 };
236
237 bpfjit_func_t code;
238 bool arg = false;
239 uint8_t pkt[1] = { 0 };
240 bpf_args_t args = { pkt, sizeof(pkt), sizeof(pkt), NULL, &arg };
241
242 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
243
244 //CHECK(bpf_validate(insns, insn_count));
245
246 code = bpfjit_generate_code(&ctx, insns, insn_count);
247 REQUIRE(code != NULL);
248
249 CHECK(code(&ctx, &args) == 0);
250 CHECK(arg == true);
251
252 bpfjit_free_code(code);
253 }
254
255 static void
test_copx_invalid_index(void)256 test_copx_invalid_index(void)
257 {
258 static struct bpf_insn insns[] = {
259 BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
260 BPF_STMT(BPF_MISC+BPF_COPX, 0),
261 BPF_STMT(BPF_RET+BPF_K, 27)
262 };
263
264 bpfjit_func_t code;
265 uint8_t pkt[1] = { 0 };
266 bpf_args_t args = { pkt, sizeof(pkt), sizeof(pkt) };
267
268 size_t insn_count = sizeof(insns) / sizeof(insns[0]);
269
270 //CHECK(bpf_validate(insns, insn_count));
271
272 code = bpfjit_generate_code(&ctx, insns, insn_count);
273 REQUIRE(code != NULL);
274
275 CHECK(code(&ctx, &args) == 0);
276
277 bpfjit_free_code(code);
278 }
279
280 void
test_copx(void)281 test_copx(void)
282 {
283
284 test_copx_no_ctx();
285 test_copx_ret_A();
286 test_copx_ret_buflen();
287 test_copx_ret_wirelen();
288 test_copx_ret_nfuncs();
289 test_copx_mixed_with_ld();
290 test_copx_invalid_index();
291 /* XXX test unreachable BPF_COPX insn. */
292 }
293