This is an archive of the discontinued LLVM Phabricator instance.

[X86] Prevent -mibt-seal to work together with -flto=thin
AbandonedPublic

Authored by joaomoreira on Dec 14 2022, 10:32 AM.

Details

Summary

As pointed out by @samitolvanen and then confirmed by @nickdesaulniers here - https://github.com/ClangBuiltLinux/linux/issues/1737 - -flto=thin does not reliably know about address-taken properties across different translation units. This breaks the assumptions behind the -mibt-seal optimization, that removes ENDBR instructions from prologues of functions which are observed as non-address-taken.

Thus, because of the above, prevent -mibt-seal from being used together with -flto=thin by only enabling it if lto is Full.

Diff Detail

Event Timeline

joaomoreira created this revision.Dec 14 2022, 10:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptDec 14 2022, 10:32 AM
Herald added a subscriber: inglorion. · View Herald Transcript
joaomoreira requested review of this revision.Dec 14 2022, 10:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptDec 14 2022, 10:32 AM

Regarding https://github.com/ClangBuiltLinux/linux/issues/1737:

Weirdly enough, I double-tested the behavior for -flto=thin + -mibt-seal; the kernel did boot fine on my setup, but when dumped/grep'ed for ENDBRs, it had ~500 less ENDBRs throughout the binary. Considering that LTO-based optimizations applied with -flto=thin should have also been applied with -flto (which means, things like dead-code elimination should be symmetrical in both generated binaries), and also given the confirmation that -flto=thin won't properly keep address-taken details across translation units, my understanding is that -mibt-seal must be disabled when -flto=thin. Thus, submitted the patch even though I was not able to reproduce the bad behavior.

samitolvanen added a comment.EditedDec 14 2022, 10:49 AM

Regarding https://github.com/ClangBuiltLinux/linux/issues/1737:

Weirdly enough, I double-tested the behavior for -flto=thin + -mibt-seal; the kernel did boot fine on my setup, but when dumped/grep'ed for ENDBRs, it had ~500 less ENDBRs throughout the binary

Did you confirm the issue with the reproducer in the CBL bug? It would be interesting to find out why you couldn't reproduce this in the kernel.

Weirdly enough, I double-tested the behavior for -flto=thin + -mibt-seal; the kernel did boot fine on my setup, but when dumped/grep'ed for ENDBRs, it had ~500 less ENDBRs throughout the binary

Did you confirm the issue with the reproducer in the CBL bug? It would be interesting to find out why you couldn't reproduce this in the kernel.

Yes, the reproducer from CBL highlights the issue. I tested it long ago and forgot to add the detail here, yet it should by itself suffice as a motivation for this fix. Thanks for bringing that up.

Regarding not being able to reproduce this in kernel -- never mind... I was misled by setup issues while running IBT kernels in QEMU. I managed to fix the setup and confirm that kernel won't boot. Thanks for pushing this bit too.

Also, FWIIW, objtool alerts about a bunch of relocations pointing to !endbr instructions when compiling with -flto=thin. When compiling with -flto+-mibt-seal, the only alert is for a data relocation to !non-endbr towards x86_64_start_kernel, which doesn't seem to be a concern since (already under the fixed setup) the kernel still doesn't trip.

samitolvanen accepted this revision.Dec 15 2022, 11:48 AM

Regarding not being able to reproduce this in kernel -- never mind... I was misled by setup issues while running IBT kernels in QEMU. I managed to fix the setup and confirm that kernel won't boot.

OK, great. Thanks for double checking!

The patch itself looks good to me, but I suspect ibt-seal in general has the same issue as D138337 where it can drop endbr instructions from isUsedInRegularObj symbols that are not address-taken in the bitcode (e.g. functions whose address is only taken in stand-alone assembly). I saw this issue only in the arm64 Linux kernel, but there's always a chance a similar code pattern emerges on the x86 side at some point in future too. This can obviously be worked around in the kernel, but just something to keep in mind.

clang/lib/Frontend/CompilerInvocation.cpp
1856

Please run git clang-format for the patch.

This revision is now accepted and ready to land.Dec 15 2022, 11:48 AM

Regarding not being able to reproduce this in kernel -- never mind... I was misled by setup issues while running IBT kernels in QEMU. I managed to fix the setup and confirm that kernel won't boot.

OK, great. Thanks for double checking!

The patch itself looks good to me, but I suspect ibt-seal in general has the same issue as D138337 where it can drop endbr instructions from isUsedInRegularObj symbols that are not address-taken in the bitcode (e.g. functions whose address is only taken in stand-alone assembly). I saw this issue only in the arm64 Linux kernel, but there's always a chance a similar code pattern emerges on the x86 side at some point in future too. This can obviously be worked around in the kernel, but just something to keep in mind.

Ugh, yeah. I reproduced the behavior with a .s and a .C file on a similar scheme as the repro you wrote for the thin lto problem. I'll start looking for a fix once I'm back from vacation in Jan. Tks for pointing this out.

joaomoreira planned changes to this revision.Dec 15 2022, 1:52 PM

I did not notice this patch (and https://github.com/ClangBuiltLinux/linux/issues/1737#issuecomment-1310741237) but make a comment yesterday while studying CFI schemes in llvm-project: https://reviews.llvm.org/D116070#4004060

As mentioned, the isUsedInRegularObj issue makes -mibt-seal not working with regular LTO as well. So it works with neither LTO mode.
I suggest that we remove the option until the issues are all sorted out.

Given https://reviews.llvm.org/D140363, this patch is being abandoned.

joaomoreira abandoned this revision.Dec 22 2022, 2:09 PM