ClangBuiltLinux/linux

CFI: asan.module_ctor is missing a type hash

samitolvanen opened this issue · 9 comments

From Mark Rutland:

Looks like CFI && KASAN is borked on both arm64 and x86; the implicitly-generated asan.module_ctor functions aren't given a type hash by the compiler, so when those get invoked by do_ctors() the calls fail

cc @kees @nickdesaulniers @nathanchance @lvwr

The asan.module_ctor function is created in the asan LLVM pass using createSanitizerCtor. Since this happens outside of Clang, it's a bit awkward to generate a type hash for the function at this point.

The reason we didn't have this problem earlier was that do_ctors is an __init function and CFI was disabled for it. I'm leaning towards simply marking the function __nocfi instead of hardcoding a type hash for these functions or hacking something together in LLVM to compute a hash. Thoughts?

Perhaps setting the types in LLVM is reasonable after all, as we'd have to deal with module constructors as well otherwise. Here's an alternative solution: https://reviews.llvm.org/D138945

The remaining issue with CFI+KASAN is that asan.module_ctor still won't have a type hash in object files that were not compiled with -fsanitize=kcfi. With x86/arm64 defconfigs, it looks like only the constructor in kernel/cfi.o trips KASAN, but I don't see any reason we couldn't now enable CFI also for kernel/cfi.c.

CFI+KASAN still fails on x86 because asan.module_ctor doesn't have the same patchable-function-prefix as the other functions, and KCFI assumes all functions have the same number of prefix nops, as discussed in #1744.

https://reviews.llvm.org/rGfd5e26270660 fixes the patchable-function-prefix issue on x86.

However... when x86 implemented FineIBT, they also added CFI hash randomization, which is still broken with KASAN. This is because even though objtool is run against vmlinux.o to build the .cfi_sites section that contains hash locations, there are two additional object files linked into the final vmlinux binary that both contain asan.module_ctor constructors: .vmlinux.export.o and init/version-timestamp.o. Since objtool didn't see these files, any type hashes in them are not in .cfi_sites, and thus they won't get randomized, which leads to a CFI failure as soon as do_ctors calls them.

cfi=norand can be used to work around this issue, but I suspect we should just disable KASAN for these files. Or perhaps make sure objtool processes them too?