OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sandbox/linux/seccomp-bpf/codegen.h" | 5 #include "sandbox/linux/seccomp-bpf/codegen.h" |
6 | 6 |
7 #include <linux/filter.h> | 7 #include <linux/filter.h> |
8 | 8 |
9 #include <map> | 9 #include <map> |
10 #include <utility> | 10 #include <utility> |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 | 109 |
110 // MakeInstruction calls CodeGen::MakeInstruction() and associated | 110 // MakeInstruction calls CodeGen::MakeInstruction() and associated |
111 // the returned address with a hash of the instruction. | 111 // the returned address with a hash of the instruction. |
112 CodeGen::Node MakeInstruction(uint16_t code, | 112 CodeGen::Node MakeInstruction(uint16_t code, |
113 uint32_t k, | 113 uint32_t k, |
114 CodeGen::Node jt = CodeGen::kNullNode, | 114 CodeGen::Node jt = CodeGen::kNullNode, |
115 CodeGen::Node jf = CodeGen::kNullNode) { | 115 CodeGen::Node jf = CodeGen::kNullNode) { |
116 CodeGen::Node res = gen_.MakeInstruction(code, k, jt, jf); | 116 CodeGen::Node res = gen_.MakeInstruction(code, k, jt, jf); |
117 EXPECT_NE(CodeGen::kNullNode, res); | 117 EXPECT_NE(CodeGen::kNullNode, res); |
118 | 118 |
119 Hash digest; | 119 Hash digest(code, k, Lookup(jt), Lookup(jf)); |
120 if (code == BPF_JMP + BPF_JA) { | |
121 // TODO(mdempsky): Disallow use of JA. | |
122 digest = Lookup(jt); | |
123 } else { | |
124 digest = Hash(code, k, Lookup(jt), Lookup(jf)); | |
125 } | |
126 auto it = node_hashes_.insert(std::make_pair(res, digest)); | 120 auto it = node_hashes_.insert(std::make_pair(res, digest)); |
127 EXPECT_EQ(digest, it.first->second); | 121 EXPECT_EQ(digest, it.first->second); |
128 | 122 |
129 return res; | 123 return res; |
130 } | 124 } |
131 | 125 |
132 // RunTest compiles the program and verifies that the output matches | 126 // RunTest compiles the program and verifies that the output matches |
133 // what is expected. It should be called at the end of each program | 127 // what is expected. It should be called at the end of each program |
134 // test case. | 128 // test case. |
135 void RunTest(CodeGen::Node head) { | 129 void RunTest(CodeGen::Node head) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 // JUMP if eq 42 the $0 else $1 (insn6) | 211 // JUMP if eq 42 the $0 else $1 (insn6) |
218 // 0: LD 23 (insn5) | 212 // 0: LD 23 (insn5) |
219 // 1: JUMP if eq 42 then $2 else $4 (insn4) | 213 // 1: JUMP if eq 42 then $2 else $4 (insn4) |
220 // 2: JUMP to $3 (insn2) | 214 // 2: JUMP to $3 (insn2) |
221 // 3: LD 42 (insn1) | 215 // 3: LD 42 (insn1) |
222 // RET 42 (insn0) | 216 // RET 42 (insn0) |
223 // 4: LD 42 (insn3) | 217 // 4: LD 42 (insn3) |
224 // RET 42 (insn3+) | 218 // RET 42 (insn3+) |
225 CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42); | 219 CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42); |
226 CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0); | 220 CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0); |
227 CodeGen::Node insn2 = MakeInstruction(BPF_JMP + BPF_JA, 0, insn1); | 221 CodeGen::Node insn2 = insn1; // Implicit JUMP |
228 | 222 |
229 // We explicitly duplicate instructions so that MergeTails() can coalesce | 223 // We explicitly duplicate instructions to test that they're merged. |
230 // them later. | |
231 CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, | 224 CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, |
232 MakeInstruction(BPF_RET + BPF_K, 42)); | 225 MakeInstruction(BPF_RET + BPF_K, 42)); |
| 226 EXPECT_EQ(insn2, insn3); |
233 | 227 |
234 CodeGen::Node insn4 = | 228 CodeGen::Node insn4 = |
235 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3); | 229 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3); |
236 CodeGen::Node insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4); | 230 CodeGen::Node insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4); |
237 | 231 |
238 // Force a basic block that ends in neither a jump instruction nor a return | 232 // Force a basic block that ends in neither a jump instruction nor a return |
239 // instruction. It only contains "insn5". This exercises one of the less | 233 // instruction. It only contains "insn5". This exercises one of the less |
240 // common code paths in the topo-sort algorithm. | 234 // common code paths in the topo-sort algorithm. |
241 // This also gives us a diamond-shaped pattern in our graph, which stresses | 235 // This also gives us a diamond-shaped pattern in our graph, which stresses |
242 // another aspect of the topo-sort algorithm (namely, the ability to | 236 // another aspect of the topo-sort algorithm (namely, the ability to |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7); | 315 CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7); |
322 CodeGen::Node i4 = MakeInstruction(BPF_RET + BPF_K, 42); | 316 CodeGen::Node i4 = MakeInstruction(BPF_RET + BPF_K, 42); |
323 CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5); | 317 CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5); |
324 CodeGen::Node i2 = MakeInstruction(BPF_RET + BPF_K, 42); | 318 CodeGen::Node i2 = MakeInstruction(BPF_RET + BPF_K, 42); |
325 CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3); | 319 CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3); |
326 CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1); | 320 CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1); |
327 | 321 |
328 RunTest(i0); | 322 RunTest(i0); |
329 } | 323 } |
330 | 324 |
| 325 TEST_F(ProgramTest, InstructionFolding) { |
| 326 // Check that simple instructions are folded as expected. |
| 327 CodeGen::Node a = MakeInstruction(BPF_RET + BPF_K, 0); |
| 328 EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0)); |
| 329 CodeGen::Node b = MakeInstruction(BPF_RET + BPF_K, 1); |
| 330 EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0)); |
| 331 EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1)); |
| 332 EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1)); |
| 333 |
| 334 // Check that complex sequences are folded too. |
| 335 CodeGen::Node c = |
| 336 MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, |
| 337 MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b)); |
| 338 EXPECT_EQ(c, MakeInstruction( |
| 339 BPF_LD + BPF_W + BPF_ABS, 0, |
| 340 MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b))); |
| 341 |
| 342 RunTest(c); |
| 343 } |
| 344 |
| 345 TEST_F(ProgramTest, FarBranches) { |
| 346 // BPF instructions use 8-bit fields for branch offsets, which means |
| 347 // branch targets must be within 255 instructions of the branch |
| 348 // instruction. CodeGen abstracts away this detail by inserting jump |
| 349 // instructions as needed, which we test here by generating programs |
| 350 // that should trigger any interesting boundary conditions. |
| 351 |
| 352 // Populate with 260 initial instruction nodes. |
| 353 std::vector<CodeGen::Node> nodes; |
| 354 nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0)); |
| 355 for (size_t i = 1; i < 260; ++i) { |
| 356 nodes.push_back( |
| 357 MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back())); |
| 358 } |
| 359 |
| 360 // Exhaustively test branch offsets near BPF's limits. |
| 361 for (size_t jt = 250; jt < 260; ++jt) { |
| 362 for (size_t jf = 250; jf < 260; ++jf) { |
| 363 nodes.push_back(MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0, |
| 364 nodes.rbegin()[jt], nodes.rbegin()[jf])); |
| 365 RunTest(nodes.back()); |
| 366 } |
| 367 } |
| 368 } |
| 369 |
331 } // namespace | 370 } // namespace |
332 } // namespace sandbox | 371 } // namespace sandbox |
OLD | NEW |