Commit d0acc76a authored by Masahiro Yamada's avatar Masahiro Yamada

modpost: remove broken calculation of exception_table_entry size

find_extable_entry_size() is completely broken. It has awesome comments
about how to calculate sizeof(struct exception_table_entry).

It was based on these assumptions:

  - struct exception_table_entry has two fields
  - both of the fields have the same size

Then, we came up with this equation:

  (offset of the second field) * 2 == (size of struct)

It was true for all architectures when commit 52dc0595 ("modpost:
handle relocations mismatch in __ex_table.") was applied.

Our mathematics broke when commit 548acf19 ("x86/mm: Expand the
exception table logic to allow new handling options") introduced the
third field.

Now, the definition of exception_table_entry is highly arch-dependent.

For x86, sizeof(struct exception_table_entry) is apparently 12, but
find_extable_entry_size() sets extable_entry_size to 8.

I could fix it, but I do not see much value in this code.

extable_entry_size is used just for selecting a slightly different
error message.

If the first field ("insn") references to a non-executable section,

    The relocation at %s+0x%lx references
    section "%s" which is not executable, IOW
    it is not possible for the kernel to fault
    at that address.  Something is seriously wrong
    and should be fixed.

If the second field ("fixup") references to a non-executable section,

    The relocation at %s+0x%lx references
    section "%s" which is not executable, IOW
    the kernel will fault if it ever tries to
    jump to it.  Something is seriously wrong
    and should be fixed.

Merge the two error messages rather than adding even more complexity.

Change fatal() to error() to make it continue running and catch more
possible errors.

Fixes: 548acf19 ("x86/mm: Expand the exception table logic to allow new handling options")
Signed-off-by: default avatarMasahiro Yamada <masahiroy@kernel.org>
parent 64f14041
...@@ -1292,43 +1292,6 @@ static int is_executable_section(struct elf_info* elf, unsigned int section_inde ...@@ -1292,43 +1292,6 @@ static int is_executable_section(struct elf_info* elf, unsigned int section_inde
return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR);
} }
/*
* We rely on a gross hack in section_rel[a]() calling find_extable_entry_size()
* to know the sizeof(struct exception_table_entry) for the target architecture.
*/
static unsigned int extable_entry_size = 0;
static void find_extable_entry_size(const char* const sec, const Elf_Rela* r)
{
/*
* If we're currently checking the second relocation within __ex_table,
* that relocation offset tells us the offsetof(struct
* exception_table_entry, fixup) which is equal to sizeof(struct
* exception_table_entry) divided by two. We use that to our advantage
* since there's no portable way to get that size as every architecture
* seems to go with different sized types. Not pretty but better than
* hard-coding the size for every architecture..
*/
if (!extable_entry_size)
extable_entry_size = r->r_offset * 2;
}
static inline bool is_extable_fault_address(Elf_Rela *r)
{
/*
* extable_entry_size is only discovered after we've handled the
* _second_ relocation in __ex_table, so only abort when we're not
* handling the first reloc and extable_entry_size is zero.
*/
if (r->r_offset && extable_entry_size == 0)
fatal("extable_entry size hasn't been discovered!\n");
return ((r->r_offset == 0) ||
(r->r_offset % extable_entry_size == 0));
}
#define is_second_extable_reloc(Start, Cur, Sec) \
(((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0))
static void report_extable_warnings(const char* modname, struct elf_info* elf, static void report_extable_warnings(const char* modname, struct elf_info* elf,
const struct sectioncheck* const mismatch, const struct sectioncheck* const mismatch,
Elf_Rela* r, Elf_Sym* sym, Elf_Rela* r, Elf_Sym* sym,
...@@ -1384,22 +1347,9 @@ static void extable_mismatch_handler(const char* modname, struct elf_info *elf, ...@@ -1384,22 +1347,9 @@ static void extable_mismatch_handler(const char* modname, struct elf_info *elf,
"You might get more information about where this is\n" "You might get more information about where this is\n"
"coming from by using scripts/check_extable.sh %s\n", "coming from by using scripts/check_extable.sh %s\n",
fromsec, (long)r->r_offset, tosec, modname); fromsec, (long)r->r_offset, tosec, modname);
else if (!is_executable_section(elf, get_secindex(elf, sym))) { else if (!is_executable_section(elf, get_secindex(elf, sym)))
if (is_extable_fault_address(r)) error("%s+0x%lx references non-executable section '%s'\n",
fatal("The relocation at %s+0x%lx references\n" fromsec, (long)r->r_offset, tosec);
"section \"%s\" which is not executable, IOW\n"
"it is not possible for the kernel to fault\n"
"at that address. Something is seriously wrong\n"
"and should be fixed.\n",
fromsec, (long)r->r_offset, tosec);
else
fatal("The relocation at %s+0x%lx references\n"
"section \"%s\" which is not executable, IOW\n"
"the kernel will fault if it ever tries to\n"
"jump to it. Something is seriously wrong\n"
"and should be fixed.\n",
fromsec, (long)r->r_offset, tosec);
}
} }
static void check_section_mismatch(const char *modname, struct elf_info *elf, static void check_section_mismatch(const char *modname, struct elf_info *elf,
...@@ -1574,8 +1524,6 @@ static void section_rela(const char *modname, struct elf_info *elf, ...@@ -1574,8 +1524,6 @@ static void section_rela(const char *modname, struct elf_info *elf,
/* Skip special sections */ /* Skip special sections */
if (is_shndx_special(sym->st_shndx)) if (is_shndx_special(sym->st_shndx))
continue; continue;
if (is_second_extable_reloc(start, rela, fromsec))
find_extable_entry_size(fromsec, &r);
check_section_mismatch(modname, elf, &r, sym, fromsec); check_section_mismatch(modname, elf, &r, sym, fromsec);
} }
} }
...@@ -1635,8 +1583,6 @@ static void section_rel(const char *modname, struct elf_info *elf, ...@@ -1635,8 +1583,6 @@ static void section_rel(const char *modname, struct elf_info *elf,
/* Skip special sections */ /* Skip special sections */
if (is_shndx_special(sym->st_shndx)) if (is_shndx_special(sym->st_shndx))
continue; continue;
if (is_second_extable_reloc(start, rel, fromsec))
find_extable_entry_size(fromsec, &r);
check_section_mismatch(modname, elf, &r, sym, fromsec); check_section_mismatch(modname, elf, &r, sym, fromsec);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment