1 /*-
2  * Copyright (c) 2012 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 #include <bpfjit.h>
31 
32 #include <stdint.h>
33 #include <string.h>
34 
35 #include "util.h"
36 #include "tests.h"
37 
38 static void
test_stx1(void)39 test_stx1(void)
40 {
41 	static struct bpf_insn insns[] = {
42 		BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
43 		BPF_STMT(BPF_STX, 0),
44 		BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0),
45 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
46 		BPF_STMT(BPF_RET+BPF_A, 0)
47 	};
48 
49 	size_t i;
50 	bpfjit_func_t code;
51 	uint8_t pkt[16]; /* the program doesn't read any data */
52 
53 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
54 
55 	CHECK(bpf_validate(insns, insn_count));
56 
57 	code = bpfjit_generate_code(NULL, insns, insn_count);
58 	REQUIRE(code != NULL);
59 
60 	for (i = 1; i <= sizeof(pkt); i++)
61 		CHECK(jitcall(code, pkt, i, sizeof(pkt)) == i);
62 
63 	bpfjit_free_code(code);
64 }
65 
66 static void
test_stx2(void)67 test_stx2(void)
68 {
69 	static struct bpf_insn insns[] = {
70 		BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
71 		BPF_STMT(BPF_STX, BPF_MEMWORDS-1),
72 		BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0),
73 		BPF_STMT(BPF_MISC+BPF_TXA, 0),
74 		BPF_STMT(BPF_RET+BPF_A, 0)
75 	};
76 
77 	bpfjit_func_t code;
78 	uint8_t pkt[1]; /* the program doesn't read any data */
79 
80 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
81 
82 	CHECK(bpf_validate(insns, insn_count));
83 
84 	code = bpfjit_generate_code(NULL, insns, insn_count);
85 	REQUIRE(code != NULL);
86 
87 	CHECK(jitcall(code, pkt, 1, 1) == 0);
88 
89 	bpfjit_free_code(code);
90 }
91 
92 static void
test_stx3(void)93 test_stx3(void)
94 {
95 	static struct bpf_insn insns[] = {
96 		BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
97 		BPF_STMT(BPF_STX, 5),
98 		BPF_STMT(BPF_STX, 2),
99 		BPF_STMT(BPF_STX, 3),
100 		BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 1),
101 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
102 		BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 2),
103 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
104 		BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 3),
105 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
106 		BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 5),
107 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
108 		BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 6),
109 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
110 		BPF_STMT(BPF_RET+BPF_A, 0)
111 	};
112 
113 	size_t i;
114 	bpfjit_func_t code;
115 	uint8_t pkt[16]; /* the program doesn't read any data */
116 
117 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
118 
119 	CHECK(bpf_validate(insns, insn_count));
120 
121 	code = bpfjit_generate_code(NULL, insns, insn_count);
122 	REQUIRE(code != NULL);
123 
124 	for (i = 1; i <= sizeof(pkt); i++)
125 		CHECK(jitcall(code, pkt, i, sizeof(pkt)) == 3 * i);
126 
127 	bpfjit_free_code(code);
128 }
129 
130 static void
test_stx4(void)131 test_stx4(void)
132 {
133 	struct bpf_insn insns[5*BPF_MEMWORDS+2];
134 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
135 
136 	size_t k;
137 	bpfjit_func_t code;
138 	uint8_t pkt[BPF_MEMWORDS]; /* the program doesn't read any data */
139 
140 	memset(insns, 0, sizeof(insns));
141 
142 	/* for each k do M[k] = k */
143 	for (k = 0; k < BPF_MEMWORDS; k++) {
144 		insns[2*k].code   = BPF_LDX+BPF_W+BPF_IMM;
145 		insns[2*k].k      = 3*k;
146 		insns[2*k+1].code = BPF_STX;
147 		insns[2*k+1].k    = k;
148 	}
149 
150 	/* load wirelen into A */
151 	insns[2*BPF_MEMWORDS].code = BPF_LD+BPF_W+BPF_LEN;
152 
153 	/* for each k, if (A == k + 1) return M[k] */
154 	for (k = 0; k < BPF_MEMWORDS; k++) {
155 		insns[2*BPF_MEMWORDS+3*k+1].code = BPF_JMP+BPF_JEQ+BPF_K;
156 		insns[2*BPF_MEMWORDS+3*k+1].k    = k+1;
157 		insns[2*BPF_MEMWORDS+3*k+1].jt   = 0;
158 		insns[2*BPF_MEMWORDS+3*k+1].jf   = 2;
159 		insns[2*BPF_MEMWORDS+3*k+2].code = BPF_LD+BPF_MEM;
160 		insns[2*BPF_MEMWORDS+3*k+2].k    = k;
161 		insns[2*BPF_MEMWORDS+3*k+3].code = BPF_RET+BPF_A;
162 		insns[2*BPF_MEMWORDS+3*k+3].k    = 0;
163 	}
164 
165 	insns[5*BPF_MEMWORDS+1].code = BPF_RET+BPF_K;
166 	insns[5*BPF_MEMWORDS+1].k    = UINT32_MAX;
167 
168 	CHECK(bpf_validate(insns, insn_count));
169 
170 	code = bpfjit_generate_code(NULL, insns, insn_count);
171 	REQUIRE(code != NULL);
172 
173 	for (k = 1; k <= sizeof(pkt); k++)
174 		CHECK(jitcall(code, pkt, k, k) == 3*(k-1));
175 
176 	bpfjit_free_code(code);
177 }
178 
179 void
test_stx(void)180 test_stx(void)
181 {
182 
183 	test_stx1();
184 	test_stx2();
185 	test_stx3();
186 	test_stx4();
187 }
188