This is a note to let you know that I've just added the patch titled modpost: remove broken calculation of exception_table_entry size to the 5.15-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: modpost-remove-broken-calculation-of-exception_table.patch and it can be found in the queue-5.15 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. commit b2fe5982b68981b4a2bc0b4941b9407f6aadc132 Author: Masahiro Yamada <masahiroy@xxxxxxxxxx> Date: Mon May 15 00:27:19 2023 +0900 modpost: remove broken calculation of exception_table_entry size [ Upstream commit d0acc76a49aa917c1a455d11d32d34a01e8b2835 ] 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 52dc0595d540 ("modpost: handle relocations mismatch in __ex_table.") was applied. Our mathematics broke when commit 548acf19234d ("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: 548acf19234d ("x86/mm: Expand the exception table logic to allow new handling options") Signed-off-by: Masahiro Yamada <masahiroy@xxxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index b284ee01fdebb..b29af4ad08321 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1612,43 +1612,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); } -/* - * 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, const struct sectioncheck* const mismatch, Elf_Rela* r, Elf_Sym* sym, @@ -1705,22 +1668,9 @@ static void extable_mismatch_handler(const char* modname, struct elf_info *elf, "You might get more information about where this is\n" "coming from by using scripts/check_extable.sh %s\n", fromsec, (long)r->r_offset, tosec, modname); - else if (!is_executable_section(elf, get_secindex(elf, sym))) { - if (is_extable_fault_address(r)) - fatal("The relocation at %s+0x%lx references\n" - "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); - } + else if (!is_executable_section(elf, get_secindex(elf, sym))) + error("%s+0x%lx references non-executable section '%s'\n", + fromsec, (long)r->r_offset, tosec); } static void check_section_mismatch(const char *modname, struct elf_info *elf, @@ -1871,8 +1821,6 @@ static void section_rela(const char *modname, struct elf_info *elf, /* Skip special sections */ if (is_shndx_special(sym->st_shndx)) continue; - if (is_second_extable_reloc(start, rela, fromsec)) - find_extable_entry_size(fromsec, &r); check_section_mismatch(modname, elf, &r, sym, fromsec); } } @@ -1931,8 +1879,6 @@ static void section_rel(const char *modname, struct elf_info *elf, /* Skip special sections */ if (is_shndx_special(sym->st_shndx)) continue; - if (is_second_extable_reloc(start, rel, fromsec)) - find_extable_entry_size(fromsec, &r); check_section_mismatch(modname, elf, &r, sym, fromsec); } }