• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include <errno.h>
6 
7 #include <algorithm>
8 #include <set>
9 #include <vector>
10 
11 #include "sandbox/linux/seccomp-bpf/codegen.h"
12 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
13 #include "sandbox/linux/tests/unit_tests.h"
14 
15 namespace sandbox {
16 
17 class SandboxUnittestHelper : public SandboxBPF {
18  public:
19   typedef SandboxBPF::Program Program;
20 };
21 
22 // We want to access some of the private methods in the code generator. We
23 // do so by defining a "friend" that makes these methods public for us.
24 class CodeGenUnittestHelper : public CodeGen {
25  public:
FindBranchTargets(const Instruction & instructions,BranchTargets * branch_targets)26   void FindBranchTargets(const Instruction& instructions,
27                          BranchTargets* branch_targets) {
28     CodeGen::FindBranchTargets(instructions, branch_targets);
29   }
30 
CutGraphIntoBasicBlocks(Instruction * insns,const BranchTargets & branch_targets,TargetsToBlocks * blocks)31   BasicBlock* CutGraphIntoBasicBlocks(Instruction* insns,
32                                       const BranchTargets& branch_targets,
33                                       TargetsToBlocks* blocks) {
34     return CodeGen::CutGraphIntoBasicBlocks(insns, branch_targets, blocks);
35   }
36 
MergeTails(TargetsToBlocks * blocks)37   void MergeTails(TargetsToBlocks* blocks) { CodeGen::MergeTails(blocks); }
38 };
39 
40 enum { NO_FLAGS = 0x0000, HAS_MERGEABLE_TAILS = 0x0001, };
41 
SampleProgramOneInstruction(CodeGen * codegen,int * flags)42 Instruction* SampleProgramOneInstruction(CodeGen* codegen, int* flags) {
43   // Create the most basic valid BPF program:
44   //    RET ERR_ALLOWED
45   *flags = NO_FLAGS;
46   return codegen->MakeInstruction(BPF_RET + BPF_K,
47                                   ErrorCode(ErrorCode::ERR_ALLOWED));
48 }
49 
SampleProgramSimpleBranch(CodeGen * codegen,int * flags)50 Instruction* SampleProgramSimpleBranch(CodeGen* codegen, int* flags) {
51   // Create a program with a single branch:
52   //    JUMP if eq 42 then $0 else $1
53   // 0: RET EPERM
54   // 1: RET ERR_ALLOWED
55   *flags = NO_FLAGS;
56   return codegen->MakeInstruction(
57       BPF_JMP + BPF_JEQ + BPF_K,
58       42,
59       codegen->MakeInstruction(BPF_RET + BPF_K, ErrorCode(EPERM)),
60       codegen->MakeInstruction(BPF_RET + BPF_K,
61                                ErrorCode(ErrorCode::ERR_ALLOWED)));
62 }
63 
SampleProgramAtypicalBranch(CodeGen * codegen,int * flags)64 Instruction* SampleProgramAtypicalBranch(CodeGen* codegen, int* flags) {
65   // Create a program with a single branch:
66   //    JUMP if eq 42 then $0 else $0
67   // 0: RET ERR_ALLOWED
68 
69   // N.B.: As the instructions in both sides of the branch are already
70   //       the same object, we do not actually have any "mergeable" branches.
71   //       This needs to be reflected in our choice of "flags".
72   *flags = NO_FLAGS;
73 
74   Instruction* ret = codegen->MakeInstruction(
75       BPF_RET + BPF_K, ErrorCode(ErrorCode::ERR_ALLOWED));
76   return codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret);
77 }
78 
SampleProgramComplex(CodeGen * codegen,int * flags)79 Instruction* SampleProgramComplex(CodeGen* codegen, int* flags) {
80   // Creates a basic BPF program that we'll use to test some of the code:
81   //    JUMP if eq 42 the $0 else $1     (insn6)
82   // 0: LD 23                            (insn5)
83   // 1: JUMP if eq 42 then $2 else $4    (insn4)
84   // 2: JUMP to $3                       (insn1)
85   // 3: LD 42                            (insn0)
86   //    RET ErrorCode(42)                (insn2)
87   // 4: LD 42                            (insn3)
88   //    RET ErrorCode(42)                (insn3+)
89   *flags = HAS_MERGEABLE_TAILS;
90 
91   Instruction* insn0 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42);
92   SANDBOX_ASSERT(insn0);
93   SANDBOX_ASSERT(insn0->code == BPF_LD + BPF_W + BPF_ABS);
94   SANDBOX_ASSERT(insn0->k == 42);
95   SANDBOX_ASSERT(insn0->next == NULL);
96 
97   Instruction* insn1 = codegen->MakeInstruction(BPF_JMP + BPF_JA, 0, insn0);
98   SANDBOX_ASSERT(insn1);
99   SANDBOX_ASSERT(insn1->code == BPF_JMP + BPF_JA);
100   SANDBOX_ASSERT(insn1->jt_ptr == insn0);
101 
102   Instruction* insn2 = codegen->MakeInstruction(BPF_RET + BPF_K, ErrorCode(42));
103   SANDBOX_ASSERT(insn2);
104   SANDBOX_ASSERT(insn2->code == BPF_RET + BPF_K);
105   SANDBOX_ASSERT(insn2->next == NULL);
106 
107   // We explicitly duplicate instructions so that MergeTails() can coalesce
108   // them later.
109   Instruction* insn3 = codegen->MakeInstruction(
110       BPF_LD + BPF_W + BPF_ABS,
111       42,
112       codegen->MakeInstruction(BPF_RET + BPF_K, ErrorCode(42)));
113 
114   Instruction* insn4 =
115       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn1, insn3);
116   SANDBOX_ASSERT(insn4);
117   SANDBOX_ASSERT(insn4->code == BPF_JMP + BPF_JEQ + BPF_K);
118   SANDBOX_ASSERT(insn4->k == 42);
119   SANDBOX_ASSERT(insn4->jt_ptr == insn1);
120   SANDBOX_ASSERT(insn4->jf_ptr == insn3);
121 
122   codegen->JoinInstructions(insn0, insn2);
123   SANDBOX_ASSERT(insn0->next == insn2);
124 
125   Instruction* insn5 =
126       codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4);
127   SANDBOX_ASSERT(insn5);
128   SANDBOX_ASSERT(insn5->code == BPF_LD + BPF_W + BPF_ABS);
129   SANDBOX_ASSERT(insn5->k == 23);
130   SANDBOX_ASSERT(insn5->next == insn4);
131 
132   // Force a basic block that ends in neither a jump instruction nor a return
133   // instruction. It only contains "insn5". This exercises one of the less
134   // common code paths in the topo-sort algorithm.
135   // This also gives us a diamond-shaped pattern in our graph, which stresses
136   // another aspect of the topo-sort algorithm (namely, the ability to
137   // correctly count the incoming branches for subtrees that are not disjunct).
138   Instruction* insn6 =
139       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn5, insn4);
140 
141   return insn6;
142 }
143 
SampleProgramConfusingTails(CodeGen * codegen,int * flags)144 Instruction* SampleProgramConfusingTails(CodeGen* codegen, int* flags) {
145   // This simple program demonstrates https://crbug.com/351103/
146   // The two "LOAD 0" instructions are blocks of their own. MergeTails() could
147   // be tempted to merge them since they are the same. However, they are
148   // not mergeable because they fall-through to non semantically equivalent
149   // blocks.
150   // Without the fix for this bug, this program should trigger the check in
151   // CompileAndCompare: the serialized graphs from the program and its compiled
152   // version will differ.
153   //
154   //  0) LOAD 1  // ???
155   //  1) if A == 0x1; then JMP 2 else JMP 3
156   //  2) LOAD 0  // System call number
157   //  3) if A == 0x2; then JMP 4 else JMP 5
158   //  4) LOAD 0  // System call number
159   //  5) if A == 0x1; then JMP 6 else JMP 7
160   //  6) RET 0x50000  // errno = 0
161   //  7) RET 0x50001  // errno = 1
162   *flags = NO_FLAGS;
163 
164   Instruction* i7 = codegen->MakeInstruction(BPF_RET, ErrorCode(1));
165   Instruction* i6 = codegen->MakeInstruction(BPF_RET, ErrorCode(0));
166   Instruction* i5 =
167       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
168   Instruction* i4 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
169   Instruction* i3 =
170       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
171   Instruction* i2 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
172   Instruction* i1 =
173       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
174   Instruction* i0 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
175 
176   return i0;
177 }
178 
SampleProgramConfusingTailsBasic(CodeGen * codegen,int * flags)179 Instruction* SampleProgramConfusingTailsBasic(CodeGen* codegen, int* flags) {
180   // Without the fix for https://crbug.com/351103/, (see
181   // SampleProgramConfusingTails()), this would generate a cyclic graph and
182   // crash as the two "LOAD 0" instructions would get merged.
183   //
184   // 0) LOAD 1  // ???
185   // 1) if A == 0x1; then JMP 2 else JMP 3
186   // 2) LOAD 0  // System call number
187   // 3) if A == 0x2; then JMP 4 else JMP 5
188   // 4) LOAD 0  // System call number
189   // 5) RET 0x50001  // errno = 1
190   *flags = NO_FLAGS;
191 
192   Instruction* i5 = codegen->MakeInstruction(BPF_RET, ErrorCode(1));
193   Instruction* i4 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
194   Instruction* i3 =
195       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
196   Instruction* i2 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
197   Instruction* i1 =
198       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
199   Instruction* i0 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
200 
201   return i0;
202 }
203 
SampleProgramConfusingTailsMergeable(CodeGen * codegen,int * flags)204 Instruction* SampleProgramConfusingTailsMergeable(CodeGen* codegen,
205                                                   int* flags) {
206   // This is similar to SampleProgramConfusingTails(), except that
207   // instructions 2 and 4 are now RET instructions.
208   // In PointerCompare(), this exercises the path where two blocks are of the
209   // same length and identical and the last instruction is a JMP or RET, so the
210   // following blocks don't need to be looked at and the blocks are mergeable.
211   //
212   // 0) LOAD 1  // ???
213   // 1) if A == 0x1; then JMP 2 else JMP 3
214   // 2) RET 0x5002a  // errno = 42
215   // 3) if A == 0x2; then JMP 4 else JMP 5
216   // 4) RET 0x5002a  // errno = 42
217   // 5) if A == 0x1; then JMP 6 else JMP 7
218   // 6) RET 0x50000  // errno = 0
219   // 7) RET 0x50001  // errno = 1
220   *flags = HAS_MERGEABLE_TAILS;
221 
222   Instruction* i7 = codegen->MakeInstruction(BPF_RET, ErrorCode(1));
223   Instruction* i6 = codegen->MakeInstruction(BPF_RET, ErrorCode(0));
224   Instruction* i5 =
225       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
226   Instruction* i4 = codegen->MakeInstruction(BPF_RET, ErrorCode(42));
227   Instruction* i3 =
228       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
229   Instruction* i2 = codegen->MakeInstruction(BPF_RET, ErrorCode(42));
230   Instruction* i1 =
231       codegen->MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
232   Instruction* i0 = codegen->MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
233 
234   return i0;
235 }
ForAllPrograms(void (* test)(CodeGenUnittestHelper *,Instruction *,int))236 void ForAllPrograms(void (*test)(CodeGenUnittestHelper*, Instruction*, int)) {
237   Instruction* (*function_table[])(CodeGen* codegen, int* flags) = {
238     SampleProgramOneInstruction,
239     SampleProgramSimpleBranch,
240     SampleProgramAtypicalBranch,
241     SampleProgramComplex,
242     SampleProgramConfusingTails,
243     SampleProgramConfusingTailsBasic,
244     SampleProgramConfusingTailsMergeable,
245   };
246 
247   for (size_t i = 0; i < arraysize(function_table); ++i) {
248     CodeGenUnittestHelper codegen;
249     int flags = NO_FLAGS;
250     Instruction *prg = function_table[i](&codegen, &flags);
251     test(&codegen, prg, flags);
252   }
253 }
254 
MakeInstruction(CodeGenUnittestHelper * codegen,Instruction * program,int)255 void MakeInstruction(CodeGenUnittestHelper* codegen,
256                      Instruction* program, int) {
257   // Nothing to do here
258 }
259 
SANDBOX_TEST(CodeGen,MakeInstruction)260 SANDBOX_TEST(CodeGen, MakeInstruction) {
261   ForAllPrograms(MakeInstruction);
262 }
263 
FindBranchTargets(CodeGenUnittestHelper * codegen,Instruction * prg,int)264 void FindBranchTargets(CodeGenUnittestHelper* codegen, Instruction* prg, int) {
265   BranchTargets branch_targets;
266   codegen->FindBranchTargets(*prg, &branch_targets);
267 
268   // Verifying the general properties that should be true for every
269   // well-formed BPF program.
270   // Perform a depth-first traversal of the BPF program an verify that all
271   // targets of BPF_JMP instructions are represented in the "branch_targets".
272   // At the same time, compute a set of both the branch targets and all the
273   // instructions in the program.
274   std::vector<Instruction*> stack;
275   std::set<Instruction*> all_instructions;
276   std::set<Instruction*> target_instructions;
277   BranchTargets::const_iterator end = branch_targets.end();
278   for (Instruction* insn = prg;;) {
279     all_instructions.insert(insn);
280     if (BPF_CLASS(insn->code) == BPF_JMP) {
281       target_instructions.insert(insn->jt_ptr);
282       SANDBOX_ASSERT(insn->jt_ptr != NULL);
283       SANDBOX_ASSERT(branch_targets.find(insn->jt_ptr) != end);
284       if (BPF_OP(insn->code) != BPF_JA) {
285         target_instructions.insert(insn->jf_ptr);
286         SANDBOX_ASSERT(insn->jf_ptr != NULL);
287         SANDBOX_ASSERT(branch_targets.find(insn->jf_ptr) != end);
288         stack.push_back(insn->jf_ptr);
289       }
290       insn = insn->jt_ptr;
291     } else if (BPF_CLASS(insn->code) == BPF_RET) {
292       SANDBOX_ASSERT(insn->next == NULL);
293       if (stack.empty()) {
294         break;
295       }
296       insn = stack.back();
297       stack.pop_back();
298     } else {
299       SANDBOX_ASSERT(insn->next != NULL);
300       insn = insn->next;
301     }
302   }
303   SANDBOX_ASSERT(target_instructions.size() == branch_targets.size());
304 
305   // We can now subtract the set of the branch targets from the set of all
306   // instructions. This gives us a set with the instructions that nobody
307   // ever jumps to. Verify that they are no included in the
308   // "branch_targets" that FindBranchTargets() computed for us.
309   Instructions non_target_instructions(all_instructions.size() -
310                                        target_instructions.size());
311   set_difference(all_instructions.begin(),
312                  all_instructions.end(),
313                  target_instructions.begin(),
314                  target_instructions.end(),
315                  non_target_instructions.begin());
316   for (Instructions::const_iterator iter = non_target_instructions.begin();
317        iter != non_target_instructions.end();
318        ++iter) {
319     SANDBOX_ASSERT(branch_targets.find(*iter) == end);
320   }
321 }
322 
SANDBOX_TEST(CodeGen,FindBranchTargets)323 SANDBOX_TEST(CodeGen, FindBranchTargets) { ForAllPrograms(FindBranchTargets); }
324 
CutGraphIntoBasicBlocks(CodeGenUnittestHelper * codegen,Instruction * prg,int)325 void CutGraphIntoBasicBlocks(CodeGenUnittestHelper* codegen,
326                              Instruction* prg,
327                              int) {
328   BranchTargets branch_targets;
329   codegen->FindBranchTargets(*prg, &branch_targets);
330   TargetsToBlocks all_blocks;
331   BasicBlock* first_block =
332       codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks);
333   SANDBOX_ASSERT(first_block != NULL);
334   SANDBOX_ASSERT(first_block->instructions.size() > 0);
335   Instruction* first_insn = first_block->instructions[0];
336 
337   // Basic blocks are supposed to start with a branch target and end with
338   // either a jump or a return instruction. It can also end, if the next
339   // instruction forms the beginning of a new basic block. There should be
340   // no other jumps or return instructions in the middle of a basic block.
341   for (TargetsToBlocks::const_iterator bb_iter = all_blocks.begin();
342        bb_iter != all_blocks.end();
343        ++bb_iter) {
344     BasicBlock* bb = bb_iter->second;
345     SANDBOX_ASSERT(bb != NULL);
346     SANDBOX_ASSERT(bb->instructions.size() > 0);
347     Instruction* insn = bb->instructions[0];
348     SANDBOX_ASSERT(insn == first_insn ||
349                    branch_targets.find(insn) != branch_targets.end());
350     for (Instructions::const_iterator insn_iter = bb->instructions.begin();;) {
351       insn = *insn_iter;
352       if (++insn_iter != bb->instructions.end()) {
353         SANDBOX_ASSERT(BPF_CLASS(insn->code) != BPF_JMP);
354         SANDBOX_ASSERT(BPF_CLASS(insn->code) != BPF_RET);
355       } else {
356         SANDBOX_ASSERT(BPF_CLASS(insn->code) == BPF_JMP ||
357                        BPF_CLASS(insn->code) == BPF_RET ||
358                        branch_targets.find(insn->next) != branch_targets.end());
359         break;
360       }
361       SANDBOX_ASSERT(branch_targets.find(*insn_iter) == branch_targets.end());
362     }
363   }
364 }
365 
SANDBOX_TEST(CodeGen,CutGraphIntoBasicBlocks)366 SANDBOX_TEST(CodeGen, CutGraphIntoBasicBlocks) {
367   ForAllPrograms(CutGraphIntoBasicBlocks);
368 }
369 
MergeTails(CodeGenUnittestHelper * codegen,Instruction * prg,int flags)370 void MergeTails(CodeGenUnittestHelper* codegen, Instruction* prg, int flags) {
371   BranchTargets branch_targets;
372   codegen->FindBranchTargets(*prg, &branch_targets);
373   TargetsToBlocks all_blocks;
374   BasicBlock* first_block =
375       codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks);
376 
377   // The shape of our graph and thus the function of our program should
378   // still be unchanged after we run MergeTails(). We verify this by
379   // serializing the graph and verifying that it is still the same.
380   // We also verify that at least some of the edges changed because of
381   // tail merging.
382   std::string graph[2];
383   std::string edges[2];
384 
385   // The loop executes twice. After the first run, we call MergeTails() on
386   // our graph.
387   for (int i = 0;;) {
388     // Traverse the entire program in depth-first order.
389     std::vector<BasicBlock*> stack;
390     for (BasicBlock* bb = first_block;;) {
391       // Serialize the instructions in this basic block. In general, we only
392       // need to serialize "code" and "k"; except for a BPF_JA instruction
393       // where "k" isn't set.
394       // The stream of instructions should be unchanged after MergeTails().
395       for (Instructions::const_iterator iter = bb->instructions.begin();
396            iter != bb->instructions.end();
397            ++iter) {
398         graph[i].append(reinterpret_cast<char*>(&(*iter)->code),
399                         sizeof((*iter)->code));
400         if (BPF_CLASS((*iter)->code) != BPF_JMP ||
401             BPF_OP((*iter)->code) != BPF_JA) {
402           graph[i].append(reinterpret_cast<char*>(&(*iter)->k),
403                           sizeof((*iter)->k));
404         }
405       }
406 
407       // Also serialize the addresses the basic blocks as we encounter them.
408       // This will change as basic blocks are coalesed by MergeTails().
409       edges[i].append(reinterpret_cast<char*>(&bb), sizeof(bb));
410 
411       // Depth-first traversal of the graph. We only ever need to look at the
412       // very last instruction in the basic block, as that is the only one that
413       // can change code flow.
414       Instruction* insn = bb->instructions.back();
415       if (BPF_CLASS(insn->code) == BPF_JMP) {
416         // For jump instructions, we need to remember the "false" branch while
417         // traversing the "true" branch. This is not necessary for BPF_JA which
418         // only has a single branch.
419         if (BPF_OP(insn->code) != BPF_JA) {
420           stack.push_back(all_blocks[insn->jf_ptr]);
421         }
422         bb = all_blocks[insn->jt_ptr];
423       } else if (BPF_CLASS(insn->code) == BPF_RET) {
424         // After a BPF_RET, see if we need to back track.
425         if (stack.empty()) {
426           break;
427         }
428         bb = stack.back();
429         stack.pop_back();
430       } else {
431         // For "normal" instructions, just follow to the next basic block.
432         bb = all_blocks[insn->next];
433       }
434     }
435 
436     // Our loop runs exactly two times.
437     if (++i > 1) {
438       break;
439     }
440     codegen->MergeTails(&all_blocks);
441   }
442   SANDBOX_ASSERT(graph[0] == graph[1]);
443   if (flags & HAS_MERGEABLE_TAILS) {
444     SANDBOX_ASSERT(edges[0] != edges[1]);
445   } else {
446     SANDBOX_ASSERT(edges[0] == edges[1]);
447   }
448 }
449 
SANDBOX_TEST(CodeGen,MergeTails)450 SANDBOX_TEST(CodeGen, MergeTails) {
451   ForAllPrograms(MergeTails);
452 }
453 
CompileAndCompare(CodeGenUnittestHelper * codegen,Instruction * prg,int)454 void CompileAndCompare(CodeGenUnittestHelper* codegen, Instruction* prg, int) {
455   // TopoSortBasicBlocks() has internal checks that cause it to fail, if it
456   // detects a problem. Typically, if anything goes wrong, this looks to the
457   // TopoSort algorithm as if there had been cycles in the input data.
458   // This provides a pretty good unittest.
459   // We hand-crafted the program returned by SampleProgram() to exercise
460   // several of the more interesting code-paths. See comments in
461   // SampleProgram() for details.
462   // In addition to relying on the internal consistency checks in the compiler,
463   // we also serialize the graph and the resulting BPF program and compare
464   // them. With the exception of BPF_JA instructions that might have been
465   // inserted, both instruction streams should be equivalent.
466   // As Compile() modifies the instructions, we have to serialize the graph
467   // before calling Compile().
468   std::string source;
469   Instructions source_stack;
470   for (const Instruction* insn = prg, *next; insn; insn = next) {
471     if (BPF_CLASS(insn->code) == BPF_JMP) {
472       if (BPF_OP(insn->code) == BPF_JA) {
473         // Do not serialize BPF_JA instructions (see above).
474         next = insn->jt_ptr;
475         continue;
476       } else {
477         source_stack.push_back(insn->jf_ptr);
478         next = insn->jt_ptr;
479       }
480     } else if (BPF_CLASS(insn->code) == BPF_RET) {
481       if (source_stack.empty()) {
482         next = NULL;
483       } else {
484         next = source_stack.back();
485         source_stack.pop_back();
486       }
487     } else {
488       next = insn->next;
489     }
490     // Only serialize "code" and "k". That's all the information we need to
491     // compare. The rest of the information is encoded in the order of
492     // instructions.
493     source.append(reinterpret_cast<const char*>(&insn->code),
494                   sizeof(insn->code));
495     source.append(reinterpret_cast<const char*>(&insn->k), sizeof(insn->k));
496   }
497 
498   // Compile the program
499   SandboxUnittestHelper::Program bpf;
500   codegen->Compile(prg, &bpf);
501 
502   // Serialize the resulting BPF instructions.
503   std::string assembly;
504   std::vector<int> assembly_stack;
505   for (int idx = 0; idx >= 0;) {
506     SANDBOX_ASSERT(idx < (int)bpf.size());
507     struct sock_filter& insn = bpf[idx];
508     if (BPF_CLASS(insn.code) == BPF_JMP) {
509       if (BPF_OP(insn.code) == BPF_JA) {
510         // Do not serialize BPF_JA instructions (see above).
511         idx += insn.k + 1;
512         continue;
513       } else {
514         assembly_stack.push_back(idx + insn.jf + 1);
515         idx += insn.jt + 1;
516       }
517     } else if (BPF_CLASS(insn.code) == BPF_RET) {
518       if (assembly_stack.empty()) {
519         idx = -1;
520       } else {
521         idx = assembly_stack.back();
522         assembly_stack.pop_back();
523       }
524     } else {
525       ++idx;
526     }
527     // Serialize the same information that we serialized before compilation.
528     assembly.append(reinterpret_cast<char*>(&insn.code), sizeof(insn.code));
529     assembly.append(reinterpret_cast<char*>(&insn.k), sizeof(insn.k));
530   }
531   SANDBOX_ASSERT(source == assembly);
532 }
533 
SANDBOX_TEST(CodeGen,All)534 SANDBOX_TEST(CodeGen, All) {
535   ForAllPrograms(CompileAndCompare);
536 }
537 
538 }  // namespace sandbox
539