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 <stdio.h> | 5 #include <stdio.h> |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "sandbox/linux/seccomp-bpf/codegen.h" | 8 #include "sandbox/linux/seccomp-bpf/codegen.h" |
9 | 9 |
10 namespace { | 10 namespace { |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
436 // Basic blocks should never be empty. | 436 // Basic blocks should never be empty. |
437 CHECK(!insns1.empty()); | 437 CHECK(!insns1.empty()); |
438 CHECK(!insns2.empty()); | 438 CHECK(!insns2.empty()); |
439 | 439 |
440 Instructions::const_iterator iter1 = insns1.begin(); | 440 Instructions::const_iterator iter1 = insns1.begin(); |
441 Instructions::const_iterator iter2 = insns2.begin(); | 441 Instructions::const_iterator iter2 = insns2.begin(); |
442 for (;; ++iter1, ++iter2) { | 442 for (;; ++iter1, ++iter2) { |
443 // If we have reached the end of the sequence of instructions in one or | 443 // If we have reached the end of the sequence of instructions in one or |
444 // both basic blocks, we know the relative ordering between the two blocks | 444 // both basic blocks, we know the relative ordering between the two blocks |
445 // and can return. | 445 // and can return. |
446 if (iter1 == insns1.end()) { | 446 if (iter1 == insns1.end() || iter2 == insns2.end()) { |
447 if (iter2 == insns2.end()) { | 447 if (iter1 != insns1.end()) { |
448 // If the two blocks are the same length (and have elementwise-equal | 448 return 1; |
449 // code and k fields, which is the only way we can reach this point), | |
450 // and the last instruction isn't a JMP or a RET, then we must compare | |
451 // their successors. | |
452 Instruction* const insns1_last = insns1.back(); | |
453 Instruction* const insns2_last = insns2.back(); | |
454 if (BPF_CLASS(insns1_last->code) != BPF_JMP && | |
455 BPF_CLASS(insns1_last->code) != BPF_RET) { | |
456 // Non jumping instructions will always have a valid next instruction. | |
457 CHECK(insns1_last->next); | |
458 CHECK(insns2_last->next); | |
459 return PointerCompare(blocks.find(insns1_last->next)->second, | |
460 blocks.find(insns2_last->next)->second, | |
461 blocks); | |
462 } else { | |
463 return 0; | |
464 } | |
465 } | 449 } |
466 return -1; | 450 if (iter2 != insns2.end()) { |
467 } else if (iter2 == insns2.end()) { | 451 return -1; |
468 return 1; | 452 } |
| 453 |
| 454 // If the two blocks are the same length (and have elementwise-equal code |
| 455 // and k fields) and their last instructions are neither a JMP nor a RET |
| 456 // (which is the only way we can reach this point), then we must compare |
| 457 // their successors. |
| 458 Instruction* const insns1_last = insns1.back(); |
| 459 Instruction* const insns2_last = insns2.back(); |
| 460 CHECK(BPF_CLASS(insns1_last->code) != BPF_JMP && |
| 461 BPF_CLASS(insns1_last->code) != BPF_RET); |
| 462 |
| 463 // Non jumping instructions will always have a valid next instruction. |
| 464 CHECK(insns1_last->next); |
| 465 CHECK(insns2_last->next); |
| 466 return PointerCompare(blocks.find(insns1_last->next)->second, |
| 467 blocks.find(insns2_last->next)->second, |
| 468 blocks); |
469 } | 469 } |
470 | 470 |
471 // Compare the individual fields for both instructions. | 471 // Compare the individual fields for both instructions. |
472 const Instruction& insn1 = **iter1; | 472 const Instruction& insn1 = **iter1; |
473 const Instruction& insn2 = **iter2; | 473 const Instruction& insn2 = **iter2; |
474 if (insn1.code == insn2.code) { | 474 if (insn1.code != insn2.code) { |
475 if (insn1.k == insn2.k) { | |
476 // Only conditional jump instructions use the jt_ptr and jf_ptr | |
477 // fields. | |
478 if (BPF_CLASS(insn1.code) == BPF_JMP) { | |
479 if (BPF_OP(insn1.code) != BPF_JA) { | |
480 // Recursively compare the "true" and "false" branches. | |
481 // A well-formed BPF program can't have any cycles, so we know | |
482 // that our recursive algorithm will ultimately terminate. | |
483 // In the unlikely event that the programmer made a mistake and | |
484 // went out of the way to give us a cyclic program, we will crash | |
485 // with a stack overflow. We are OK with that. | |
486 int c = PointerCompare(blocks.find(insn1.jt_ptr)->second, | |
487 blocks.find(insn2.jt_ptr)->second, | |
488 blocks); | |
489 if (c == 0) { | |
490 c = PointerCompare(blocks.find(insn1.jf_ptr)->second, | |
491 blocks.find(insn2.jf_ptr)->second, | |
492 blocks); | |
493 if (c == 0) { | |
494 continue; | |
495 } else { | |
496 return c; | |
497 } | |
498 } else { | |
499 return c; | |
500 } | |
501 } else { | |
502 int c = PointerCompare(blocks.find(insn1.jt_ptr)->second, | |
503 blocks.find(insn2.jt_ptr)->second, | |
504 blocks); | |
505 if (c == 0) { | |
506 continue; | |
507 } else { | |
508 return c; | |
509 } | |
510 } | |
511 } else { | |
512 continue; | |
513 } | |
514 } else { | |
515 return insn1.k - insn2.k; | |
516 } | |
517 } else { | |
518 return insn1.code - insn2.code; | 475 return insn1.code - insn2.code; |
519 } | 476 } |
| 477 if (insn1.k != insn2.k) { |
| 478 return insn1.k - insn2.k; |
| 479 } |
| 480 |
| 481 // Sanity check: If we're looking at a JMP or RET instruction, by definition |
| 482 // it should be the last instruction of the basic block. |
| 483 if (BPF_CLASS(insn1.code) == BPF_JMP || BPF_CLASS(insn1.code) == BPF_RET) { |
| 484 CHECK_EQ(insns1.back(), &insn1); |
| 485 CHECK_EQ(insns2.back(), &insn2); |
| 486 } |
| 487 |
| 488 // RET instructions terminate execution, and only JMP instructions use the |
| 489 // jt_ptr and jf_ptr fields. Anything else can continue to the next |
| 490 // instruction in the basic block. |
| 491 if (BPF_CLASS(insn1.code) == BPF_RET) { |
| 492 return 0; |
| 493 } else if (BPF_CLASS(insn1.code) != BPF_JMP) { |
| 494 continue; |
| 495 } |
| 496 |
| 497 // Recursively compare the "true" and "false" branches. |
| 498 // A well-formed BPF program can't have any cycles, so we know |
| 499 // that our recursive algorithm will ultimately terminate. |
| 500 // In the unlikely event that the programmer made a mistake and |
| 501 // went out of the way to give us a cyclic program, we will crash |
| 502 // with a stack overflow. We are OK with that. |
| 503 if (BPF_OP(insn1.code) != BPF_JA) { |
| 504 int c = PointerCompare(blocks.find(insn1.jf_ptr)->second, |
| 505 blocks.find(insn2.jf_ptr)->second, |
| 506 blocks); |
| 507 if (c != 0) { |
| 508 return c; |
| 509 } |
| 510 } |
| 511 return PointerCompare(blocks.find(insn1.jt_ptr)->second, |
| 512 blocks.find(insn2.jt_ptr)->second, |
| 513 blocks); |
520 } | 514 } |
521 } | 515 } |
522 | 516 |
523 void CodeGen::MergeTails(TargetsToBlocks* blocks) { | 517 void CodeGen::MergeTails(TargetsToBlocks* blocks) { |
524 // We enter all of our basic blocks into a set using the BasicBlock::Less() | 518 // We enter all of our basic blocks into a set using the BasicBlock::Less() |
525 // comparator. This naturally results in blocks with identical tails of | 519 // comparator. This naturally results in blocks with identical tails of |
526 // instructions to map to the same entry in the set. Whenever we discover | 520 // instructions to map to the same entry in the set. Whenever we discover |
527 // that a particular chain of instructions is already in the set, we merge | 521 // that a particular chain of instructions is already in the set, we merge |
528 // the basic blocks and update the pointer in the "blocks" map. | 522 // the basic blocks and update the pointer in the "blocks" map. |
529 // Returns the number of unique basic blocks. | 523 // Returns the number of unique basic blocks. |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
765 CutGraphIntoBasicBlocks(instructions, branch_targets, &all_blocks); | 759 CutGraphIntoBasicBlocks(instructions, branch_targets, &all_blocks); |
766 MergeTails(&all_blocks); | 760 MergeTails(&all_blocks); |
767 BasicBlocks basic_blocks; | 761 BasicBlocks basic_blocks; |
768 TopoSortBasicBlocks(first_block, all_blocks, &basic_blocks); | 762 TopoSortBasicBlocks(first_block, all_blocks, &basic_blocks); |
769 ComputeRelativeJumps(&basic_blocks, all_blocks); | 763 ComputeRelativeJumps(&basic_blocks, all_blocks); |
770 ConcatenateBasicBlocks(basic_blocks, program); | 764 ConcatenateBasicBlocks(basic_blocks, program); |
771 return; | 765 return; |
772 } | 766 } |
773 | 767 |
774 } // namespace sandbox | 768 } // namespace sandbox |
OLD | NEW |