| Index: sandbox/linux/seccomp-bpf/codegen.cc
|
| diff --git a/sandbox/linux/seccomp-bpf/codegen.cc b/sandbox/linux/seccomp-bpf/codegen.cc
|
| index c05eb5e051d634d79a93f7917c357e7f092ee2af..211e6596fcd14b9a1304ec8561262b2913801a3b 100644
|
| --- a/sandbox/linux/seccomp-bpf/codegen.cc
|
| +++ b/sandbox/linux/seccomp-bpf/codegen.cc
|
| @@ -443,80 +443,74 @@ static int PointerCompare(const BasicBlock* block1,
|
| // If we have reached the end of the sequence of instructions in one or
|
| // both basic blocks, we know the relative ordering between the two blocks
|
| // and can return.
|
| - if (iter1 == insns1.end()) {
|
| - if (iter2 == insns2.end()) {
|
| - // If the two blocks are the same length (and have elementwise-equal
|
| - // code and k fields, which is the only way we can reach this point),
|
| - // and the last instruction isn't a JMP or a RET, then we must compare
|
| - // their successors.
|
| - Instruction* const insns1_last = insns1.back();
|
| - Instruction* const insns2_last = insns2.back();
|
| - if (BPF_CLASS(insns1_last->code) != BPF_JMP &&
|
| - BPF_CLASS(insns1_last->code) != BPF_RET) {
|
| - // Non jumping instructions will always have a valid next instruction.
|
| - CHECK(insns1_last->next);
|
| - CHECK(insns2_last->next);
|
| - return PointerCompare(blocks.find(insns1_last->next)->second,
|
| - blocks.find(insns2_last->next)->second,
|
| - blocks);
|
| - } else {
|
| - return 0;
|
| - }
|
| + if (iter1 == insns1.end() || iter2 == insns2.end()) {
|
| + if (iter1 != insns1.end()) {
|
| + return 1;
|
| + }
|
| + if (iter2 != insns2.end()) {
|
| + return -1;
|
| }
|
| - return -1;
|
| - } else if (iter2 == insns2.end()) {
|
| - return 1;
|
| +
|
| + // If the two blocks are the same length (and have elementwise-equal code
|
| + // and k fields) and their last instructions are neither a JMP nor a RET
|
| + // (which is the only way we can reach this point), then we must compare
|
| + // their successors.
|
| + Instruction* const insns1_last = insns1.back();
|
| + Instruction* const insns2_last = insns2.back();
|
| + CHECK(BPF_CLASS(insns1_last->code) != BPF_JMP &&
|
| + BPF_CLASS(insns1_last->code) != BPF_RET);
|
| +
|
| + // Non jumping instructions will always have a valid next instruction.
|
| + CHECK(insns1_last->next);
|
| + CHECK(insns2_last->next);
|
| + return PointerCompare(blocks.find(insns1_last->next)->second,
|
| + blocks.find(insns2_last->next)->second,
|
| + blocks);
|
| }
|
|
|
| // Compare the individual fields for both instructions.
|
| const Instruction& insn1 = **iter1;
|
| const Instruction& insn2 = **iter2;
|
| - if (insn1.code == insn2.code) {
|
| - if (insn1.k == insn2.k) {
|
| - // Only conditional jump instructions use the jt_ptr and jf_ptr
|
| - // fields.
|
| - if (BPF_CLASS(insn1.code) == BPF_JMP) {
|
| - if (BPF_OP(insn1.code) != BPF_JA) {
|
| - // Recursively compare the "true" and "false" branches.
|
| - // A well-formed BPF program can't have any cycles, so we know
|
| - // that our recursive algorithm will ultimately terminate.
|
| - // In the unlikely event that the programmer made a mistake and
|
| - // went out of the way to give us a cyclic program, we will crash
|
| - // with a stack overflow. We are OK with that.
|
| - int c = PointerCompare(blocks.find(insn1.jt_ptr)->second,
|
| - blocks.find(insn2.jt_ptr)->second,
|
| - blocks);
|
| - if (c == 0) {
|
| - c = PointerCompare(blocks.find(insn1.jf_ptr)->second,
|
| - blocks.find(insn2.jf_ptr)->second,
|
| - blocks);
|
| - if (c == 0) {
|
| - continue;
|
| - } else {
|
| - return c;
|
| - }
|
| - } else {
|
| - return c;
|
| - }
|
| - } else {
|
| - int c = PointerCompare(blocks.find(insn1.jt_ptr)->second,
|
| - blocks.find(insn2.jt_ptr)->second,
|
| - blocks);
|
| - if (c == 0) {
|
| - continue;
|
| - } else {
|
| - return c;
|
| - }
|
| - }
|
| - } else {
|
| - continue;
|
| - }
|
| - } else {
|
| - return insn1.k - insn2.k;
|
| - }
|
| - } else {
|
| + if (insn1.code != insn2.code) {
|
| return insn1.code - insn2.code;
|
| }
|
| + if (insn1.k != insn2.k) {
|
| + return insn1.k - insn2.k;
|
| + }
|
| +
|
| + // Sanity check: If we're looking at a JMP or RET instruction, by definition
|
| + // it should be the last instruction of the basic block.
|
| + if (BPF_CLASS(insn1.code) == BPF_JMP || BPF_CLASS(insn1.code) == BPF_RET) {
|
| + CHECK_EQ(insns1.back(), &insn1);
|
| + CHECK_EQ(insns2.back(), &insn2);
|
| + }
|
| +
|
| + // RET instructions terminate execution, and only JMP instructions use the
|
| + // jt_ptr and jf_ptr fields. Anything else can continue to the next
|
| + // instruction in the basic block.
|
| + if (BPF_CLASS(insn1.code) == BPF_RET) {
|
| + return 0;
|
| + } else if (BPF_CLASS(insn1.code) != BPF_JMP) {
|
| + continue;
|
| + }
|
| +
|
| + // Recursively compare the "true" and "false" branches.
|
| + // A well-formed BPF program can't have any cycles, so we know
|
| + // that our recursive algorithm will ultimately terminate.
|
| + // In the unlikely event that the programmer made a mistake and
|
| + // went out of the way to give us a cyclic program, we will crash
|
| + // with a stack overflow. We are OK with that.
|
| + if (BPF_OP(insn1.code) != BPF_JA) {
|
| + int c = PointerCompare(blocks.find(insn1.jf_ptr)->second,
|
| + blocks.find(insn2.jf_ptr)->second,
|
| + blocks);
|
| + if (c != 0) {
|
| + return c;
|
| + }
|
| + }
|
| + return PointerCompare(blocks.find(insn1.jt_ptr)->second,
|
| + blocks.find(insn2.jt_ptr)->second,
|
| + blocks);
|
| }
|
| }
|
|
|
|
|