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 <cstring> | 9 #include <cstring> |
10 #include <map> | 10 #include <map> |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
106 | 106 |
107 // MakeInstruction calls CodeGen::MakeInstruction() and associated | 107 // MakeInstruction calls CodeGen::MakeInstruction() and associated |
108 // the returned address with a hash of the instruction. | 108 // the returned address with a hash of the instruction. |
109 CodeGen::Addr MakeInstruction(uint16_t code, | 109 CodeGen::Addr MakeInstruction(uint16_t code, |
110 uint32_t k, | 110 uint32_t k, |
111 CodeGen::Addr jt = CodeGen::kNullAddr, | 111 CodeGen::Addr jt = CodeGen::kNullAddr, |
112 CodeGen::Addr jf = CodeGen::kNullAddr) { | 112 CodeGen::Addr jf = CodeGen::kNullAddr) { |
113 CodeGen::Addr res = gen_.MakeInstruction(code, k, jt, jf); | 113 CodeGen::Addr res = gen_.MakeInstruction(code, k, jt, jf); |
114 EXPECT_NE(CodeGen::kNullAddr, res); | 114 EXPECT_NE(CodeGen::kNullAddr, res); |
115 | 115 |
116 Hash digest; | 116 Hash digest(code, k, Lookup(jt), Lookup(jf)); |
117 if (code == BPF_JMP + BPF_JA) { | |
118 // TODO(mdempsky): Disallow use of JA. | |
119 digest = Lookup(jt); | |
120 } else { | |
121 digest = Hash(code, k, Lookup(jt), Lookup(jf)); | |
122 } | |
123 auto it = addr_hashes_.insert(std::make_pair(res, digest)); | 117 auto it = addr_hashes_.insert(std::make_pair(res, digest)); |
124 EXPECT_EQ(digest, it.first->second); | 118 EXPECT_EQ(digest, it.first->second); |
125 | 119 |
126 return res; | 120 return res; |
127 } | 121 } |
128 | 122 |
129 // RunTest compiles the program and verifies that the output matches | 123 // RunTest compiles the program and verifies that the output matches |
130 // what is expected. It should be called at the end of each program | 124 // what is expected. It should be called at the end of each program |
131 // test case. | 125 // test case. |
132 void RunTest(CodeGen::Addr head) { | 126 void RunTest(CodeGen::Addr head) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
204 // the same object, we do not actually have any "mergeable" branches. | 198 // the same object, we do not actually have any "mergeable" branches. |
205 // This needs to be reflected in our choice of "flags". | 199 // This needs to be reflected in our choice of "flags". |
206 RunTest(head); | 200 RunTest(head); |
207 } | 201 } |
208 | 202 |
209 TEST_F(ProgramTest, Complex) { | 203 TEST_F(ProgramTest, Complex) { |
210 // Creates a basic BPF program that we'll use to test some of the code: | 204 // Creates a basic BPF program that we'll use to test some of the code: |
211 // JUMP if eq 42 the $0 else $1 (insn6) | 205 // JUMP if eq 42 the $0 else $1 (insn6) |
212 // 0: LD 23 (insn5) | 206 // 0: LD 23 (insn5) |
213 // 1: JUMP if eq 42 then $2 else $4 (insn4) | 207 // 1: JUMP if eq 42 then $2 else $4 (insn4) |
214 // 2: JUMP to $3 (insn2) | 208 // 2: JUMP to $3 (insn2) |
rickyz (no longer on Chrome)
2014/11/12 23:43:50
Update this comment now that we got rid of the jum
mdempsky
2014/11/18 01:07:30
So my reasoning was this is the description of the
| |
215 // 3: LD 42 (insn1) | 209 // 3: LD 42 (insn1) |
216 // RET 42 (insn0) | 210 // RET 42 (insn0) |
217 // 4: LD 42 (insn3) | 211 // 4: LD 42 (insn3) |
218 // RET 42 (insn3+) | 212 // RET 42 (insn3+) |
219 CodeGen::Addr insn0 = MakeInstruction(BPF_RET + BPF_K, 42); | 213 CodeGen::Addr insn0 = MakeInstruction(BPF_RET + BPF_K, 42); |
220 CodeGen::Addr insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0); | 214 CodeGen::Addr insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0); |
221 CodeGen::Addr insn2 = MakeInstruction(BPF_JMP + BPF_JA, 0, insn1); | 215 CodeGen::Addr insn2 = insn1; // Implicit JUMP |
222 | 216 |
223 // We explicitly duplicate instructions so that MergeTails() can coalesce | 217 // We explicitly duplicate instructions to check that CodeGen merges them. |
224 // them later. | |
225 CodeGen::Addr insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, | 218 CodeGen::Addr insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, |
226 MakeInstruction(BPF_RET + BPF_K, 42)); | 219 MakeInstruction(BPF_RET + BPF_K, 42)); |
220 EXPECT_EQ(insn2, insn3); | |
227 | 221 |
228 CodeGen::Addr insn4 = | 222 CodeGen::Addr insn4 = |
229 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3); | 223 MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3); |
230 CodeGen::Addr insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4); | 224 CodeGen::Addr insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4); |
231 | 225 |
232 // Force a basic block that ends in neither a jump instruction nor a return | 226 // Force a basic block that ends in neither a jump instruction nor a return |
233 // instruction. It only contains "insn5". This exercises one of the less | 227 // instruction. It only contains "insn5". This exercises one of the less |
234 // common code paths in the topo-sort algorithm. | 228 // common code paths in the topo-sort algorithm. |
235 // This also gives us a diamond-shaped pattern in our graph, which stresses | 229 // This also gives us a diamond-shaped pattern in our graph, which stresses |
236 // another aspect of the topo-sort algorithm (namely, the ability to | 230 // another aspect of the topo-sort algorithm (namely, the ability to |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
315 CodeGen::Addr i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7); | 309 CodeGen::Addr i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7); |
316 CodeGen::Addr i4 = MakeInstruction(BPF_RET + BPF_K, 42); | 310 CodeGen::Addr i4 = MakeInstruction(BPF_RET + BPF_K, 42); |
317 CodeGen::Addr i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5); | 311 CodeGen::Addr i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5); |
318 CodeGen::Addr i2 = MakeInstruction(BPF_RET + BPF_K, 42); | 312 CodeGen::Addr i2 = MakeInstruction(BPF_RET + BPF_K, 42); |
319 CodeGen::Addr i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3); | 313 CodeGen::Addr i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3); |
320 CodeGen::Addr i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1); | 314 CodeGen::Addr i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1); |
321 | 315 |
322 RunTest(i0); | 316 RunTest(i0); |
323 } | 317 } |
324 | 318 |
319 TEST_F(ProgramTest, InstructionFolding) { | |
320 // Check that simple instructions are folded as expected. | |
321 CodeGen::Addr a = MakeInstruction(BPF_RET + BPF_K, 0); | |
322 EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0)); | |
323 CodeGen::Addr b = MakeInstruction(BPF_RET + BPF_K, 1); | |
324 EXPECT_EQ(a, MakeInstruction(BPF_RET + BPF_K, 0)); | |
325 EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1)); | |
326 EXPECT_EQ(b, MakeInstruction(BPF_RET + BPF_K, 1)); | |
327 | |
328 // Check that complex sequences are folded too. | |
329 CodeGen::Addr c = | |
330 MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, | |
331 MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b)); | |
332 EXPECT_EQ(c, MakeInstruction( | |
333 BPF_LD + BPF_W + BPF_ABS, 0, | |
334 MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, 0x100, a, b))); | |
335 | |
336 RunTest(c); | |
337 } | |
338 | |
325 } // namespace | 339 } // namespace |
rickyz (no longer on Chrome)
2014/11/12 23:43:50
Can you add a test that calls MakeInstruction with
mdempsky
2014/11/18 01:07:30
Done.
| |
326 } // namespace sandbox | 340 } // namespace sandbox |
OLD | NEW |