• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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