From: Kees Cook keescook@chromium.org
There's an implicit dependency on the section ordering of the orphaned section .fixup that can break arm_copy_from_user if the linker places the .fixup section before the .text section. Since .fixup is not explicitly placed in the existing ARM linker scripts, the linker is free to order it anywhere with respect to the rest of the sections.
Multiple users from different distros (Raspbian, CrOS) reported kernel panics executing seccomp() syscall with Linux kernels linked with LLD.
Documentation/x86/exception-tables.rst alludes to the ordering dependency. The relevant quote:
``` NOTE: Due to the way that the exception table is built and needs to be ordered, only use exceptions for code in the .text section. Any other section will cause the exception table to not be sorted correctly, and the exceptions will fail.
Things changed when 64-bit support was added to x86 Linux. Rather than double the size of the exception table by expanding the two entries from 32-bits to 64 bits, a clever trick was used to store addresses as relative offsets from the table itself. The assembly code changed from::
.long 1b,3b to: .long (from) - . .long (to) - .
and the C-code that uses these values converts back to absolute addresses like this::
ex_insn_addr(const struct exception_table_entry *x) { return (unsigned long)&x->insn + x->insn; } ```
Since the addresses stored in the __ex_table are RELATIVE offsets and not ABSOLUTE addresses, ordering the fixup anywhere that's not immediately preceding .text causes the relative offset of the faulting instruction to be wrong, causing the wrong (or no) address of the fixup handler to looked up in __ex_table.
x86 and arm64 place the .fixup section near the end of the .text section; follow their pattern.
Cc: stable@vger.kernel.org Link: https://github.com/ClangBuiltLinux/linux/issues/282 Link: https://bugs.chromium.org/p/chromium/issues/detail?id=1020633#c36 Reported-by: Manoj Gupta manojgupta@google.com Reported-by: Nathan Chancellor natechancellor@gmail.com Signed-off-by: Kees Cook keescook@chromium.org Signed-off-by: Nick Desaulniers ndesaulniers@google.com Debugged-by: Nick Desaulniers ndesaulniers@google.com Worded-by: Nick Desaulniers ndesaulniers@google.com Tested-by: Manoj Gupta manojgupta@google.com Tested-by: Nathan Chancellor natechancellor@gmail.com --- arch/arm/kernel/vmlinux.lds.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/arm/kernel/vmlinux.lds.h b/arch/arm/kernel/vmlinux.lds.h index 8247bc15addc..e130f7668cf0 100644 --- a/arch/arm/kernel/vmlinux.lds.h +++ b/arch/arm/kernel/vmlinux.lds.h @@ -74,6 +74,7 @@ LOCK_TEXT \ HYPERVISOR_TEXT \ KPROBES_TEXT \ + *(.fixup) \ *(.gnu.warning) \ *(.glue_7) \ *(.glue_7t) \