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