1 #include "sandboxed_api/sandbox2/bpf_evaluator.h"
2
3 #include <linux/filter.h>
4
5 #include <cstdint>
6 #include <tuple>
7 #include <vector>
8
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11 #include "absl/status/status.h"
12 #include "sandboxed_api/sandbox2/util/bpf_helper.h"
13 #include "sandboxed_api/util/status_matchers.h"
14
15 namespace sandbox2::bpf {
16 namespace {
17
18 using ::testing::Eq;
19
TEST(EvaluatorTest,SimpleReturn)20 TEST(EvaluatorTest, SimpleReturn) {
21 sock_filter prog[] = {
22 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
23 };
24 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {.nr = 1}));
25 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
26 }
27
TEST(EvaluatorTest,ReturnAcumulator)28 TEST(EvaluatorTest, ReturnAcumulator) {
29 sock_filter prog[] = {
30 BPF_STMT(BPF_LD + BPF_IMM, SECCOMP_RET_ALLOW),
31 BPF_STMT(BPF_RET + BPF_A, 0),
32 };
33 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {.nr = 1}));
34 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
35 }
36
TEST(EvaluatorTest,SimpleJump)37 TEST(EvaluatorTest, SimpleJump) {
38 sock_filter prog[] = {
39 LOAD_SYSCALL_NR,
40 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 1, 0, 1),
41 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
42 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
43 };
44 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {.nr = 1}));
45 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
46 SAPI_ASSERT_OK_AND_ASSIGN(result, Evaluate(prog, {.nr = 2}));
47 EXPECT_THAT(result, Eq(SECCOMP_RET_KILL));
48 }
49
TEST(EvaluatorTest,AbsoluteJump)50 TEST(EvaluatorTest, AbsoluteJump) {
51 sock_filter prog[] = {
52 BPF_STMT(BPF_JMP + BPF_JA, 1),
53 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
54 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
55 };
56 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {.nr = 1}));
57 EXPECT_THAT(result, Eq(SECCOMP_RET_KILL));
58 }
59
TEST(EvaluatorTest,MemoryOps)60 TEST(EvaluatorTest, MemoryOps) {
61 sock_filter prog[] = {
62 BPF_STMT(BPF_LD + BPF_IMM, 0),
63 BPF_STMT(BPF_LDX + BPF_IMM, 1),
64 BPF_STMT(BPF_STX, 5),
65 BPF_STMT(BPF_LD + BPF_MEM, 5),
66 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 1, 0, 1),
67 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
68 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
69 };
70 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {}));
71 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
72 }
73
TEST(EvaluatorTest,MemoryOps2)74 TEST(EvaluatorTest, MemoryOps2) {
75 sock_filter prog[] = {
76 BPF_STMT(BPF_LDX + BPF_IMM, 1),
77 BPF_STMT(BPF_LD + BPF_IMM, 0),
78 BPF_STMT(BPF_ST, 5),
79 BPF_STMT(BPF_LDX + BPF_MEM, 5),
80 BPF_STMT(BPF_LD + BPF_IMM, 1),
81 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1),
82 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
83 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
84 };
85 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {}));
86 EXPECT_THAT(result, Eq(SECCOMP_RET_KILL));
87 }
88
TEST(EvaluatorTest,Txa)89 TEST(EvaluatorTest, Txa) {
90 sock_filter prog[] = {
91 BPF_STMT(BPF_LDX + BPF_IMM, 1),
92 BPF_STMT(BPF_LD + BPF_IMM, 0),
93 BPF_STMT(BPF_MISC + BPF_TXA, 0),
94 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 1, 0, 2),
95 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1),
96 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
97 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
98 };
99 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {}));
100 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
101 }
102
TEST(EvaluatorTest,Tax)103 TEST(EvaluatorTest, Tax) {
104 sock_filter prog[] = {
105 BPF_STMT(BPF_LDX + BPF_IMM, 1),
106 BPF_STMT(BPF_LD + BPF_IMM, 0),
107 BPF_STMT(BPF_MISC + BPF_TAX, 0),
108 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 2),
109 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1),
110 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
111 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
112 };
113 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {}));
114 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
115 }
116
TEST(EvaluatorTest,LoadLen)117 TEST(EvaluatorTest, LoadLen) {
118 sock_filter prog[] = {
119 BPF_STMT(BPF_LD + BPF_LEN, 0),
120 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct seccomp_data), 0, 1),
121 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
122 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
123 };
124 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {}));
125 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
126 }
127
TEST(EvaluatorTest,LoadLenX)128 TEST(EvaluatorTest, LoadLenX) {
129 sock_filter prog[] = {
130 BPF_STMT(BPF_LDX + BPF_LEN, 0),
131 BPF_STMT(BPF_LD + BPF_IMM, sizeof(struct seccomp_data)),
132 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1),
133 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
134 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
135 };
136 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {}));
137 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
138 }
139
TEST(EvaluatorTest,AllJumps)140 TEST(EvaluatorTest, AllJumps) {
141 std::vector<std::tuple<sock_filter, uint32_t, uint32_t>> jumps = {
142 {BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 1, 0, 1), 1, 2},
143 {BPF_JUMP(BPF_JMP + BPF_JGT + BPF_K, 1, 0, 1), 2, 1},
144 {BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, 1, 0, 1), 1, 0},
145 {BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 3, 0, 1), 2, 12},
146 };
147 for (const auto& [jmp, allow_nr, kill_nr] : jumps) {
148 std::vector<sock_filter> prog = {
149 LOAD_SYSCALL_NR,
150 };
151 prog.push_back(jmp);
152 prog.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW));
153 prog.push_back(BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL));
154 SAPI_ASSERT_OK_AND_ASSIGN(
155 uint32_t result, Evaluate(prog, {.nr = static_cast<int>(allow_nr)}));
156 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
157 SAPI_ASSERT_OK_AND_ASSIGN(
158 result, Evaluate(prog, {.nr = static_cast<int>(kill_nr)}));
159 EXPECT_THAT(result, Eq(SECCOMP_RET_KILL));
160 }
161 }
162
TEST(EvaluatorTest,Arithmetics)163 TEST(EvaluatorTest, Arithmetics) {
164 sock_filter prog[] = {
165 LOAD_SYSCALL_NR,
166 BPF_STMT(BPF_ALU + BPF_NEG, 1),
167 BPF_STMT(BPF_ALU + BPF_ADD + BPF_K, 11),
168 BPF_STMT(BPF_ALU + BPF_SUB + BPF_K, 5),
169 BPF_STMT(BPF_ALU + BPF_MUL + BPF_K, 2),
170 BPF_STMT(BPF_ALU + BPF_DIV + BPF_K, 10),
171 BPF_STMT(BPF_ALU + BPF_OR + BPF_K, 2),
172 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 1),
173 BPF_STMT(BPF_ALU + BPF_LSH + BPF_K, 4),
174 BPF_STMT(BPF_ALU + BPF_RSH + BPF_K, 1),
175 BPF_STMT(BPF_ALU + BPF_XOR + BPF_K, 17),
176 BPF_STMT(BPF_LDX + BPF_IMM, 2),
177 BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 1),
178 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 27, 0, 1),
179 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
180 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_KILL),
181 };
182 SAPI_ASSERT_OK_AND_ASSIGN(uint32_t result, Evaluate(prog, {.nr = 1}));
183 EXPECT_THAT(result, Eq(SECCOMP_RET_ALLOW));
184 SAPI_ASSERT_OK_AND_ASSIGN(result, Evaluate(prog, {.nr = 2}));
185 EXPECT_THAT(result, Eq(SECCOMP_RET_KILL));
186 }
187
TEST(EvaluatorTest,InvalidDivision)188 TEST(EvaluatorTest, InvalidDivision) {
189 sock_filter prog[] = {
190 BPF_STMT(BPF_LD + BPF_IMM, 1),
191 BPF_STMT(BPF_ALU + BPF_DIV + BPF_K, 0),
192 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
193 };
194 EXPECT_THAT(Evaluate(prog, {}),
195 sapi::StatusIs(absl::StatusCode::kInvalidArgument));
196 }
197
TEST(EvaluatorTest,InvalidAluOp)198 TEST(EvaluatorTest, InvalidAluOp) {
199 sock_filter prog[] = {
200 BPF_STMT(BPF_LD + BPF_IMM, 1),
201 BPF_STMT(BPF_ALU + 0xe0 + BPF_K, 10),
202 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
203 };
204 EXPECT_THAT(Evaluate(prog, {}),
205 sapi::StatusIs(absl::StatusCode::kInvalidArgument,
206 "Invalid instruction 228"));
207 }
208
TEST(EvaluatorTest,InvalidJump)209 TEST(EvaluatorTest, InvalidJump) {
210 sock_filter prog[] = {
211 BPF_STMT(BPF_LD + BPF_IMM, 1),
212 BPF_JUMP(BPF_JMP + 0xe0 + BPF_K, 1, 0, 0),
213 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
214 };
215 EXPECT_THAT(Evaluate(prog, {}),
216 sapi::StatusIs(absl::StatusCode::kInvalidArgument,
217 "Invalid instruction 229"));
218 }
219
TEST(EvaluatorTest,InvalidInst)220 TEST(EvaluatorTest, InvalidInst) {
221 sock_filter prog[] = {
222 BPF_STMT(BPF_ST + BPF_X, 1),
223 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
224 };
225 EXPECT_THAT(Evaluate(prog, {}),
226 sapi::StatusIs(absl::StatusCode::kInvalidArgument,
227 "Invalid instruction 10"));
228 }
229
TEST(EvaluatorTest,EmptyProgram)230 TEST(EvaluatorTest, EmptyProgram) {
231 EXPECT_THAT(Evaluate({}, {.nr = 1}),
232 sapi::StatusIs(absl::StatusCode::kInvalidArgument,
233 "Out of bounds execution"));
234 }
235
TEST(EvaluatorTest,NoReturn)236 TEST(EvaluatorTest, NoReturn) {
237 sock_filter prog[] = {
238 LOAD_SYSCALL_NR,
239 };
240 EXPECT_THAT(Evaluate(prog, {.nr = 1}),
241 sapi::StatusIs(absl::StatusCode::kInvalidArgument,
242 "Fall through to out of bounds execution"));
243 }
244
TEST(EvaluatorTest,OutOfBoundsJump)245 TEST(EvaluatorTest, OutOfBoundsJump) {
246 sock_filter prog[] = {
247 LOAD_SYSCALL_NR,
248 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 1, 0, 1),
249 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
250 };
251 EXPECT_THAT(
252 Evaluate(prog, {.nr = 2}),
253 sapi::StatusIs(absl::StatusCode::kInvalidArgument, "Out of bounds jump"));
254 }
255
TEST(EvaluatorTest,OutOfMemoryOps)256 TEST(EvaluatorTest, OutOfMemoryOps) {
257 std::vector<std::vector<sock_filter>> progs = {
258 {
259 BPF_STMT(BPF_LD + BPF_IMM, 1),
260 BPF_STMT(BPF_ST, 17),
261 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
262 },
263 {
264 BPF_STMT(BPF_LDX + BPF_IMM, 1),
265 BPF_STMT(BPF_STX, 17),
266 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
267 },
268 {
269 BPF_STMT(BPF_LD + BPF_MEM, 17),
270 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
271 },
272 {
273 BPF_STMT(BPF_LDX + BPF_MEM, 17),
274 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
275 },
276 };
277 for (const std::vector<sock_filter>& prog : progs) {
278 EXPECT_THAT(Evaluate(prog, {}),
279 sapi::StatusIs(absl::StatusCode::kInvalidArgument));
280 }
281 }
282
TEST(EvaluatorTest,MisalignedLoad)283 TEST(EvaluatorTest, MisalignedLoad) {
284 sock_filter prog[] = {
285 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 3),
286 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
287 };
288 EXPECT_THAT(Evaluate(prog, {}),
289 sapi::StatusIs(absl::StatusCode::kInvalidArgument,
290 "Misaligned read (3)"));
291 }
292
TEST(EvaluatorTest,OutOfBoundsLoad)293 TEST(EvaluatorTest, OutOfBoundsLoad) {
294 sock_filter prog[] = {
295 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 4096),
296 BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
297 };
298 EXPECT_THAT(Evaluate(prog, {}),
299 sapi::StatusIs(absl::StatusCode::kInvalidArgument,
300 "Out of bounds read (4096)"));
301 }
302
303 } // namespace
304 } // namespace sandbox2::bpf
305