diff options
| -rw-r--r-- | arch/arm/kernel/kprobes-test.c | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 6c0946c023f8..fe169e934d42 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c | |||
| @@ -178,6 +178,7 @@ | |||
| 178 | 178 | ||
| 179 | #include <linux/kernel.h> | 179 | #include <linux/kernel.h> |
| 180 | #include <linux/module.h> | 180 | #include <linux/module.h> |
| 181 | #include <linux/slab.h> | ||
| 181 | #include <linux/kprobes.h> | 182 | #include <linux/kprobes.h> |
| 182 | 183 | ||
| 183 | #include "kprobes.h" | 184 | #include "kprobes.h" |
| @@ -529,6 +530,250 @@ static int table_test(const union decode_item *table) | |||
| 529 | 530 | ||
| 530 | 531 | ||
| 531 | /* | 532 | /* |
| 533 | * Decoding table test coverage analysis | ||
| 534 | * | ||
| 535 | * coverage_start() builds a coverage_table which contains a list of | ||
| 536 | * coverage_entry's to match each entry in the specified kprobes instruction | ||
| 537 | * decoding table. | ||
| 538 | * | ||
| 539 | * When test cases are run, coverage_add() is called to process each case. | ||
| 540 | * This looks up the corresponding entry in the coverage_table and sets it as | ||
| 541 | * being matched, as well as clearing the regs flag appropriate for the test. | ||
| 542 | * | ||
| 543 | * After all test cases have been run, coverage_end() is called to check that | ||
| 544 | * all entries in coverage_table have been matched and that all regs flags are | ||
| 545 | * cleared. I.e. that all possible combinations of instructions described by | ||
| 546 | * the kprobes decoding tables have had a test case executed for them. | ||
| 547 | */ | ||
| 548 | |||
| 549 | bool coverage_fail; | ||
| 550 | |||
| 551 | #define MAX_COVERAGE_ENTRIES 256 | ||
| 552 | |||
| 553 | struct coverage_entry { | ||
| 554 | const struct decode_header *header; | ||
| 555 | unsigned regs; | ||
| 556 | unsigned nesting; | ||
| 557 | char matched; | ||
| 558 | }; | ||
| 559 | |||
| 560 | struct coverage_table { | ||
| 561 | struct coverage_entry *base; | ||
| 562 | unsigned num_entries; | ||
| 563 | unsigned nesting; | ||
| 564 | }; | ||
| 565 | |||
| 566 | struct coverage_table coverage; | ||
| 567 | |||
| 568 | #define COVERAGE_ANY_REG (1<<0) | ||
| 569 | #define COVERAGE_SP (1<<1) | ||
| 570 | #define COVERAGE_PC (1<<2) | ||
| 571 | #define COVERAGE_PCWB (1<<3) | ||
| 572 | |||
| 573 | static const char coverage_register_lookup[16] = { | ||
| 574 | [REG_TYPE_ANY] = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC, | ||
| 575 | [REG_TYPE_SAMEAS16] = COVERAGE_ANY_REG, | ||
| 576 | [REG_TYPE_SP] = COVERAGE_SP, | ||
| 577 | [REG_TYPE_PC] = COVERAGE_PC, | ||
| 578 | [REG_TYPE_NOSP] = COVERAGE_ANY_REG | COVERAGE_SP, | ||
| 579 | [REG_TYPE_NOSPPC] = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC, | ||
| 580 | [REG_TYPE_NOPC] = COVERAGE_ANY_REG | COVERAGE_PC, | ||
| 581 | [REG_TYPE_NOPCWB] = COVERAGE_ANY_REG | COVERAGE_PC | COVERAGE_PCWB, | ||
| 582 | [REG_TYPE_NOPCX] = COVERAGE_ANY_REG, | ||
| 583 | [REG_TYPE_NOSPPCX] = COVERAGE_ANY_REG | COVERAGE_SP, | ||
| 584 | }; | ||
| 585 | |||
| 586 | unsigned coverage_start_registers(const struct decode_header *h) | ||
| 587 | { | ||
| 588 | unsigned regs = 0; | ||
| 589 | int i; | ||
| 590 | for (i = 0; i < 20; i += 4) { | ||
| 591 | int r = (h->type_regs.bits >> (DECODE_TYPE_BITS + i)) & 0xf; | ||
| 592 | regs |= coverage_register_lookup[r] << i; | ||
| 593 | } | ||
| 594 | return regs; | ||
| 595 | } | ||
| 596 | |||
| 597 | static int coverage_start_fn(const struct decode_header *h, void *args) | ||
| 598 | { | ||
| 599 | struct coverage_table *coverage = (struct coverage_table *)args; | ||
| 600 | enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; | ||
| 601 | struct coverage_entry *entry = coverage->base + coverage->num_entries; | ||
| 602 | |||
| 603 | if (coverage->num_entries == MAX_COVERAGE_ENTRIES - 1) { | ||
| 604 | pr_err("FAIL: Out of space for test coverage data"); | ||
| 605 | return -ENOMEM; | ||
| 606 | } | ||
| 607 | |||
| 608 | ++coverage->num_entries; | ||
| 609 | |||
| 610 | entry->header = h; | ||
| 611 | entry->regs = coverage_start_registers(h); | ||
| 612 | entry->nesting = coverage->nesting; | ||
| 613 | entry->matched = false; | ||
| 614 | |||
| 615 | if (type == DECODE_TYPE_TABLE) { | ||
| 616 | struct decode_table *d = (struct decode_table *)h; | ||
| 617 | int ret; | ||
| 618 | ++coverage->nesting; | ||
| 619 | ret = table_iter(d->table.table, coverage_start_fn, coverage); | ||
| 620 | --coverage->nesting; | ||
| 621 | return ret; | ||
| 622 | } | ||
| 623 | |||
| 624 | return 0; | ||
| 625 | } | ||
| 626 | |||
| 627 | static int coverage_start(const union decode_item *table) | ||
| 628 | { | ||
| 629 | coverage.base = kmalloc(MAX_COVERAGE_ENTRIES * | ||
| 630 | sizeof(struct coverage_entry), GFP_KERNEL); | ||
| 631 | coverage.num_entries = 0; | ||
| 632 | coverage.nesting = 0; | ||
| 633 | return table_iter(table, coverage_start_fn, &coverage); | ||
| 634 | } | ||
| 635 | |||
| 636 | static void | ||
| 637 | coverage_add_registers(struct coverage_entry *entry, kprobe_opcode_t insn) | ||
| 638 | { | ||
| 639 | int regs = entry->header->type_regs.bits >> DECODE_TYPE_BITS; | ||
| 640 | int i; | ||
| 641 | for (i = 0; i < 20; i += 4) { | ||
| 642 | enum decode_reg_type reg_type = (regs >> i) & 0xf; | ||
| 643 | int reg = (insn >> i) & 0xf; | ||
| 644 | int flag; | ||
| 645 | |||
| 646 | if (!reg_type) | ||
| 647 | continue; | ||
| 648 | |||
| 649 | if (reg == 13) | ||
| 650 | flag = COVERAGE_SP; | ||
| 651 | else if (reg == 15) | ||
| 652 | flag = COVERAGE_PC; | ||
| 653 | else | ||
| 654 | flag = COVERAGE_ANY_REG; | ||
| 655 | entry->regs &= ~(flag << i); | ||
| 656 | |||
| 657 | switch (reg_type) { | ||
| 658 | |||
| 659 | case REG_TYPE_NONE: | ||
| 660 | case REG_TYPE_ANY: | ||
| 661 | case REG_TYPE_SAMEAS16: | ||
| 662 | break; | ||
| 663 | |||
| 664 | case REG_TYPE_SP: | ||
| 665 | if (reg != 13) | ||
| 666 | return; | ||
| 667 | break; | ||
| 668 | |||
| 669 | case REG_TYPE_PC: | ||
| 670 | if (reg != 15) | ||
| 671 | return; | ||
| 672 | break; | ||
| 673 | |||
| 674 | case REG_TYPE_NOSP: | ||
| 675 | if (reg == 13) | ||
| 676 | return; | ||
| 677 | break; | ||
| 678 | |||
| 679 | case REG_TYPE_NOSPPC: | ||
| 680 | case REG_TYPE_NOSPPCX: | ||
| 681 | if (reg == 13 || reg == 15) | ||
| 682 | return; | ||
| 683 | break; | ||
| 684 | |||
| 685 | case REG_TYPE_NOPCWB: | ||
| 686 | if (!is_writeback(insn)) | ||
| 687 | break; | ||
| 688 | if (reg == 15) { | ||
| 689 | entry->regs &= ~(COVERAGE_PCWB << i); | ||
| 690 | return; | ||
| 691 | } | ||
| 692 | break; | ||
| 693 | |||
| 694 | case REG_TYPE_NOPC: | ||
| 695 | case REG_TYPE_NOPCX: | ||
| 696 | if (reg == 15) | ||
| 697 | return; | ||
| 698 | break; | ||
| 699 | } | ||
| 700 | |||
| 701 | } | ||
| 702 | } | ||
| 703 | |||
| 704 | static void coverage_add(kprobe_opcode_t insn) | ||
| 705 | { | ||
| 706 | struct coverage_entry *entry = coverage.base; | ||
| 707 | struct coverage_entry *end = coverage.base + coverage.num_entries; | ||
| 708 | bool matched = false; | ||
| 709 | unsigned nesting = 0; | ||
| 710 | |||
| 711 | for (; entry < end; ++entry) { | ||
| 712 | const struct decode_header *h = entry->header; | ||
| 713 | enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; | ||
| 714 | |||
| 715 | if (entry->nesting > nesting) | ||
| 716 | continue; /* Skip sub-table we didn't match */ | ||
| 717 | |||
| 718 | if (entry->nesting < nesting) | ||
| 719 | break; /* End of sub-table we were scanning */ | ||
| 720 | |||
| 721 | if (!matched) { | ||
| 722 | if ((insn & h->mask.bits) != h->value.bits) | ||
| 723 | continue; | ||
| 724 | entry->matched = true; | ||
| 725 | } | ||
| 726 | |||
| 727 | switch (type) { | ||
| 728 | |||
| 729 | case DECODE_TYPE_TABLE: | ||
| 730 | ++nesting; | ||
| 731 | break; | ||
| 732 | |||
| 733 | case DECODE_TYPE_CUSTOM: | ||
| 734 | case DECODE_TYPE_SIMULATE: | ||
| 735 | case DECODE_TYPE_EMULATE: | ||
| 736 | coverage_add_registers(entry, insn); | ||
| 737 | return; | ||
| 738 | |||
| 739 | case DECODE_TYPE_OR: | ||
| 740 | matched = true; | ||
| 741 | break; | ||
| 742 | |||
| 743 | case DECODE_TYPE_REJECT: | ||
| 744 | default: | ||
| 745 | return; | ||
| 746 | } | ||
| 747 | |||
| 748 | } | ||
| 749 | } | ||
| 750 | |||
| 751 | static void coverage_end(void) | ||
| 752 | { | ||
| 753 | struct coverage_entry *entry = coverage.base; | ||
| 754 | struct coverage_entry *end = coverage.base + coverage.num_entries; | ||
| 755 | |||
| 756 | for (; entry < end; ++entry) { | ||
| 757 | u32 mask = entry->header->mask.bits; | ||
| 758 | u32 value = entry->header->value.bits; | ||
| 759 | |||
| 760 | if (entry->regs) { | ||
| 761 | pr_err("FAIL: Register test coverage missing for %08x %08x (%05x)\n", | ||
| 762 | mask, value, entry->regs); | ||
| 763 | coverage_fail = true; | ||
| 764 | } | ||
| 765 | if (!entry->matched) { | ||
| 766 | pr_err("FAIL: Test coverage entry missing for %08x %08x\n", | ||
| 767 | mask, value); | ||
| 768 | coverage_fail = true; | ||
| 769 | } | ||
| 770 | } | ||
| 771 | |||
| 772 | kfree(coverage.base); | ||
| 773 | } | ||
| 774 | |||
| 775 | |||
| 776 | /* | ||
| 532 | * Framework for instruction set test cases | 777 | * Framework for instruction set test cases |
| 533 | */ | 778 | */ |
| 534 | 779 | ||
| @@ -1039,6 +1284,8 @@ static uintptr_t __used kprobes_test_case_start(const char *title, void *stack) | |||
| 1039 | } | 1284 | } |
| 1040 | } | 1285 | } |
| 1041 | 1286 | ||
| 1287 | coverage_add(current_instruction); | ||
| 1288 | |||
| 1042 | if (end_arg->flags & ARG_FLAG_UNSUPPORTED) { | 1289 | if (end_arg->flags & ARG_FLAG_UNSUPPORTED) { |
| 1043 | if (register_test_probe(&test_case_probe) < 0) | 1290 | if (register_test_probe(&test_case_probe) < 0) |
| 1044 | goto pass; | 1291 | goto pass; |
| @@ -1213,8 +1460,13 @@ static int run_test_cases(void (*tests)(void), const union decode_item *table) | |||
| 1213 | return ret; | 1460 | return ret; |
| 1214 | 1461 | ||
| 1215 | pr_info(" Run test cases\n"); | 1462 | pr_info(" Run test cases\n"); |
| 1463 | ret = coverage_start(table); | ||
| 1464 | if (ret) | ||
| 1465 | return ret; | ||
| 1466 | |||
| 1216 | tests(); | 1467 | tests(); |
| 1217 | 1468 | ||
| 1469 | coverage_end(); | ||
| 1218 | return 0; | 1470 | return 0; |
| 1219 | } | 1471 | } |
| 1220 | 1472 | ||
| @@ -1274,6 +1526,15 @@ static int __init run_all_tests(void) | |||
| 1274 | goto out; | 1526 | goto out; |
| 1275 | } | 1527 | } |
| 1276 | 1528 | ||
| 1529 | #if __LINUX_ARM_ARCH__ >= 7 | ||
| 1530 | /* We are able to run all test cases so coverage should be complete */ | ||
| 1531 | if (coverage_fail) { | ||
| 1532 | pr_err("FAIL: Test coverage checks failed\n"); | ||
| 1533 | ret = -EINVAL; | ||
| 1534 | goto out; | ||
| 1535 | } | ||
| 1536 | #endif | ||
| 1537 | |||
| 1277 | out: | 1538 | out: |
| 1278 | if (ret == 0) | 1539 | if (ret == 0) |
| 1279 | pr_info("Finished kprobe tests OK\n"); | 1540 | pr_info("Finished kprobe tests OK\n"); |
