aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Casasnovas <quentin.casasnovas@oracle.com>2015-04-13 07:22:53 -0400
committerRusty Russell <rusty@rustcorp.com.au>2015-04-13 07:33:03 -0400
commit52dc0595d540155436d91811f929bdc8afd6a2a1 (patch)
tree9e90d8e5753fb53747bc6767156750dc659cb0c4
parentc31e4b832f124dccdb5d80ba3c1cd4f9081f7fb2 (diff)
modpost: handle relocations mismatch in __ex_table.
__ex_table is a simple table section where each entry is a pair of addresses - the first address is an address which can fault in kernel space, and the second address points to where the kernel should jump to when handling that fault. This is how copy_from_user() does not crash the kernel if userspace gives a borked pointer for example. If one of these addresses point to a non-executable section, something is seriously wrong since it either means the kernel will never fault from there or it will not be able to jump to there. As both cases are serious enough, we simply error out in these cases so the build fails and the developper has to fix the issue. In case the section is executable, but it isn't referenced in our list of authorized sections to point to from __ex_table, we just dump a warning giving more information about it. We do this in case the new section is executable but isn't supposed to be executed by the kernel. This happened with .altinstr_replacement, which is executable but is only used to copy instructions from - we should never have our instruction pointer pointing in .altinstr_replacement. Admitedly, a proper fix in that case would be to just set .altinstr_replacement NX, but we need to warn about future cases like this. Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (added long casts)
-rw-r--r--scripts/mod/modpost.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index bf0cf8173beb..e95aa28ce0f7 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -875,6 +875,8 @@ static void check_section(const char *modname, struct elf_info *elf,
875#define DATA_SECTIONS ".data", ".data.rel" 875#define DATA_SECTIONS ".data", ".data.rel"
876#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ 876#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
877 ".kprobes.text" 877 ".kprobes.text"
878#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
879 ".fixup", ".entry.text"
878 880
879#define INIT_SECTIONS ".init.*" 881#define INIT_SECTIONS ".init.*"
880#define MEM_INIT_SECTIONS ".meminit.*" 882#define MEM_INIT_SECTIONS ".meminit.*"
@@ -882,6 +884,9 @@ static void check_section(const char *modname, struct elf_info *elf,
882#define EXIT_SECTIONS ".exit.*" 884#define EXIT_SECTIONS ".exit.*"
883#define MEM_EXIT_SECTIONS ".memexit.*" 885#define MEM_EXIT_SECTIONS ".memexit.*"
884 886
887#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
888 TEXT_SECTIONS, OTHER_TEXT_SECTIONS
889
885/* init data sections */ 890/* init data sections */
886static const char *const init_data_sections[] = 891static const char *const init_data_sections[] =
887 { ALL_INIT_DATA_SECTIONS, NULL }; 892 { ALL_INIT_DATA_SECTIONS, NULL };
@@ -922,6 +927,7 @@ enum mismatch {
922 ANY_INIT_TO_ANY_EXIT, 927 ANY_INIT_TO_ANY_EXIT,
923 ANY_EXIT_TO_ANY_INIT, 928 ANY_EXIT_TO_ANY_INIT,
924 EXPORT_TO_INIT_EXIT, 929 EXPORT_TO_INIT_EXIT,
930 EXTABLE_TO_NON_TEXT,
925}; 931};
926 932
927struct sectioncheck { 933struct sectioncheck {
@@ -936,6 +942,11 @@ struct sectioncheck {
936 942
937}; 943};
938 944
945static void extable_mismatch_handler(const char *modname, struct elf_info *elf,
946 const struct sectioncheck* const mismatch,
947 Elf_Rela *r, Elf_Sym *sym,
948 const char *fromsec);
949
939static const struct sectioncheck sectioncheck[] = { 950static const struct sectioncheck sectioncheck[] = {
940/* Do not reference init/exit code/data from 951/* Do not reference init/exit code/data from
941 * normal code and data 952 * normal code and data
@@ -1013,6 +1024,16 @@ static const struct sectioncheck sectioncheck[] = {
1013 .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, 1024 .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
1014 .mismatch = EXPORT_TO_INIT_EXIT, 1025 .mismatch = EXPORT_TO_INIT_EXIT,
1015 .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, 1026 .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
1027},
1028{
1029 .fromsec = { "__ex_table", NULL },
1030 /* If you're adding any new black-listed sections in here, consider
1031 * adding a special 'printer' for them in scripts/check_extable.
1032 */
1033 .bad_tosec = { ".altinstr_replacement", NULL },
1034 .good_tosec = {ALL_TEXT_SECTIONS , NULL},
1035 .mismatch = EXTABLE_TO_NON_TEXT,
1036 .handler = extable_mismatch_handler,
1016} 1037}
1017}; 1038};
1018 1039
@@ -1418,6 +1439,10 @@ static void report_sec_mismatch(const char *modname,
1418 tosym, prl_to, prl_to, tosym); 1439 tosym, prl_to, prl_to, tosym);
1419 free(prl_to); 1440 free(prl_to);
1420 break; 1441 break;
1442 case EXTABLE_TO_NON_TEXT:
1443 fatal("There's a special handler for this mismatch type, "
1444 "we should never get here.");
1445 break;
1421 } 1446 }
1422 fprintf(stderr, "\n"); 1447 fprintf(stderr, "\n");
1423} 1448}
@@ -1453,6 +1478,120 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
1453 } 1478 }
1454} 1479}
1455 1480
1481static int is_executable_section(struct elf_info* elf, unsigned int section_index)
1482{
1483 if (section_index > elf->num_sections)
1484 fatal("section_index is outside elf->num_sections!\n");
1485
1486 return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
1487}
1488
1489/*
1490 * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
1491 * to know the sizeof(struct exception_table_entry) for the target architecture.
1492 */
1493static unsigned int extable_entry_size = 0;
1494static void find_extable_entry_size(const char* const sec, const Elf_Rela* r,
1495 const void* start, const void* cur)
1496{
1497 /*
1498 * If we're currently checking the second relocation within __ex_table,
1499 * that relocation offset tells us the offsetof(struct
1500 * exception_table_entry, fixup) which is equal to sizeof(struct
1501 * exception_table_entry) divided by two. We use that to our advantage
1502 * since there's no portable way to get that size as every architecture
1503 * seems to go with different sized types. Not pretty but better than
1504 * hard-coding the size for every architecture..
1505 */
1506 if (!extable_entry_size && cur == start + 1 &&
1507 strcmp("__ex_table", sec) == 0)
1508 extable_entry_size = r->r_offset * 2;
1509}
1510static inline bool is_extable_fault_address(Elf_Rela *r)
1511{
1512 if (!extable_entry_size == 0)
1513 fatal("extable_entry size hasn't been discovered!\n");
1514
1515 return ((r->r_offset == 0) ||
1516 (r->r_offset % extable_entry_size == 0));
1517}
1518
1519static void report_extable_warnings(const char* modname, struct elf_info* elf,
1520 const struct sectioncheck* const mismatch,
1521 Elf_Rela* r, Elf_Sym* sym,
1522 const char* fromsec, const char* tosec)
1523{
1524 Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec);
1525 const char* fromsym_name = sym_name(elf, fromsym);
1526 Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym);
1527 const char* tosym_name = sym_name(elf, tosym);
1528 const char* from_pretty_name;
1529 const char* from_pretty_name_p;
1530 const char* to_pretty_name;
1531 const char* to_pretty_name_p;
1532
1533 get_pretty_name(is_function(fromsym),
1534 &from_pretty_name, &from_pretty_name_p);
1535 get_pretty_name(is_function(tosym),
1536 &to_pretty_name, &to_pretty_name_p);
1537
1538 warn("%s(%s+0x%lx): Section mismatch in reference"
1539 " from the %s %s%s to the %s %s:%s%s\n",
1540 modname, fromsec, (long)r->r_offset, from_pretty_name,
1541 fromsym_name, from_pretty_name_p,
1542 to_pretty_name, tosec, tosym_name, to_pretty_name_p);
1543
1544 if (!match(tosec, mismatch->bad_tosec) &&
1545 is_executable_section(elf, get_secindex(elf, sym)))
1546 fprintf(stderr,
1547 "The relocation at %s+0x%lx references\n"
1548 "section \"%s\" which is not in the list of\n"
1549 "authorized sections. If you're adding a new section\n"
1550 "and/or if this reference is valid, add \"%s\" to the\n"
1551 "list of authorized sections to jump to on fault.\n"
1552 "This can be achieved by adding \"%s\" to \n"
1553 "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n",
1554 fromsec, (long)r->r_offset, tosec, tosec, tosec);
1555}
1556
1557static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
1558 const struct sectioncheck* const mismatch,
1559 Elf_Rela* r, Elf_Sym* sym,
1560 const char *fromsec)
1561{
1562 const char* tosec = sec_name(elf, get_secindex(elf, sym));
1563
1564 sec_mismatch_count++;
1565
1566 if (sec_mismatch_verbose)
1567 report_extable_warnings(modname, elf, mismatch, r, sym,
1568 fromsec, tosec);
1569
1570 if (match(tosec, mismatch->bad_tosec))
1571 fatal("The relocation at %s+0x%lx references\n"
1572 "section \"%s\" which is black-listed.\n"
1573 "Something is seriously wrong and should be fixed.\n"
1574 "You might get more information about where this is\n"
1575 "coming from by using scripts/check_extable.sh %s\n",
1576 fromsec, (long)r->r_offset, tosec, modname);
1577 else if (!is_executable_section(elf, get_secindex(elf, sym))) {
1578 if (is_extable_fault_address(r))
1579 fatal("The relocation at %s+0x%lx references\n"
1580 "section \"%s\" which is not executable, IOW\n"
1581 "it is not possible for the kernel to fault\n"
1582 "at that address. Something is seriously wrong\n"
1583 "and should be fixed.\n",
1584 fromsec, (long)r->r_offset, tosec);
1585 else
1586 fatal("The relocation at %s+0x%lx references\n"
1587 "section \"%s\" which is not executable, IOW\n"
1588 "the kernel will fault if it ever tries to\n"
1589 "jump to it. Something is seriously wrong\n"
1590 "and should be fixed.\n",
1591 fromsec, (long)r->r_offset, tosec);
1592 }
1593}
1594
1456static void check_section_mismatch(const char *modname, struct elf_info *elf, 1595static void check_section_mismatch(const char *modname, struct elf_info *elf,
1457 Elf_Rela *r, Elf_Sym *sym, const char *fromsec) 1596 Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
1458{ 1597{
@@ -1605,6 +1744,7 @@ static void section_rela(const char *modname, struct elf_info *elf,
1605 /* Skip special sections */ 1744 /* Skip special sections */
1606 if (is_shndx_special(sym->st_shndx)) 1745 if (is_shndx_special(sym->st_shndx))
1607 continue; 1746 continue;
1747 find_extable_entry_size(fromsec, &r, start, rela);
1608 check_section_mismatch(modname, elf, &r, sym, fromsec); 1748 check_section_mismatch(modname, elf, &r, sym, fromsec);
1609 } 1749 }
1610} 1750}
@@ -1663,6 +1803,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
1663 /* Skip special sections */ 1803 /* Skip special sections */
1664 if (is_shndx_special(sym->st_shndx)) 1804 if (is_shndx_special(sym->st_shndx))
1665 continue; 1805 continue;
1806 find_extable_entry_size(fromsec, &r, start, rel);
1666 check_section_mismatch(modname, elf, &r, sym, fromsec); 1807 check_section_mismatch(modname, elf, &r, sym, fromsec);
1667 } 1808 }
1668} 1809}