Home | History | Annotate | Download | only in seccomp-bpf
      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:
     26   void FindBranchTargets(const Instruction& instructions,
     27                          BranchTargets* branch_targets) {
     28     CodeGen::FindBranchTargets(instructions, branch_targets);
     29   }
     30 
     31   BasicBlock* CutGraphIntoBasicBlocks(Instruction* insns,
     32                                       const BranchTargets& branch_targets,
     33                                       TargetsToBlocks* blocks) {
     34     return CodeGen::CutGraphIntoBasicBlocks(insns, branch_targets, blocks);
     35   }
     36 
     37   void MergeTails(TargetsToBlocks* blocks) { CodeGen::MergeTails(blocks); }
     38 };
     39 
     40 enum { NO_FLAGS = 0x0000, HAS_MERGEABLE_TAILS = 0x0001, };
     41 
     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 
     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 
     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 
     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 
    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 
    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 
    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 }
    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 
    255 void MakeInstruction(CodeGenUnittestHelper* codegen,
    256                      Instruction* program, int) {
    257   // Nothing to do here
    258 }
    259 
    260 SANDBOX_TEST(CodeGen, MakeInstruction) {
    261   ForAllPrograms(MakeInstruction);
    262 }
    263 
    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 
    323 SANDBOX_TEST(CodeGen, FindBranchTargets) { ForAllPrograms(FindBranchTargets); }
    324 
    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 
    366 SANDBOX_TEST(CodeGen, CutGraphIntoBasicBlocks) {
    367   ForAllPrograms(CutGraphIntoBasicBlocks);
    368 }
    369 
    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 
    450 SANDBOX_TEST(CodeGen, MergeTails) {
    451   ForAllPrograms(MergeTails);
    452 }
    453 
    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 
    534 SANDBOX_TEST(CodeGen, All) {
    535   ForAllPrograms(CompileAndCompare);
    536 }
    537 
    538 }  // namespace sandbox
    539