This is an archive of the discontinued LLVM Phabricator instance.

Add support for kcfi-seal optimization with LTO
AcceptedPublic

Authored by samitolvanen on Nov 18 2022, 4:14 PM.

Details

Summary

With -fsanitize=kcfi, Clang emits a !kcfi_type attribute for all
global functions, making them valid indirect call targets, whether
the program ends up calling them indirectly or not. With LTO, we can
"seal" the program by dropping types from non-address-taken globals
as long as they are not visible to regular objects, thus limiting the
possible targets that can be called.

Propagate the VisibleToRegularObj property from the linker to LLVM
passes, and drop KCFI type information from globals that don't need
it.

Depends on D142163

Diff Detail

Event Timeline

samitolvanen created this revision.Nov 18 2022, 4:14 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 18 2022, 4:14 PM
samitolvanen requested review of this revision.Nov 18 2022, 4:14 PM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptNov 18 2022, 4:14 PM
nickdesaulniers accepted this revision.Dec 5 2022, 12:01 PM
This revision is now accepted and ready to land.Dec 5 2022, 12:01 PM
pcc added a comment.Dec 5 2022, 12:55 PM

Can't this be implicit if LTO is being used?

samitolvanen added a comment.EditedDec 5 2022, 1:22 PM

Can't this be implicit if LTO is being used?

I would prefer to keep this behind a flag (similarly to -mibt-seal), so we can better control when and where the optimization enabled. For example, enabling this implicitly would currently break LTO+KCFI kernel builds as the kernel has global functions that are not address-taken in C code, but still end up being indirectly called because their addresses were taken in assembly code that wasn't visible to LTO (e.g. arm64's alternative_cb mechanism).

pcc added a comment.Dec 5 2022, 3:22 PM

Can't this be implicit if LTO is being used?

I would prefer to keep this behind a flag (similarly to -mibt-seal), so we can better control when and where the optimization enabled. For example, enabling this implicitly would currently break LTO+KCFI kernel builds as the kernel has global functions that are not address-taken in C code, but still end up being indirectly called because their addresses were taken in assembly code that wasn't visible to LTO (e.g. arm64's alternative_cb mechanism).

Isn't that just a bug in the optimization? It shouldn't be applying this to symbols where VisibleToRegularObj is set.

Isn't that just a bug in the optimization? It shouldn't be applying this to symbols where VisibleToRegularObj is set.

The current patch simply replicates ibt-seal behavior, but sure, looking at symbol resolution should solve this problem. I'll take a look when have some more time.

samitolvanen planned changes to this revision.Dec 5 2022, 3:48 PM
MaskRay added a comment.EditedDec 19 2022, 5:06 PM

(Sorry for my belated response.)

If we make ThinLTO properly track combined the address-taken property, and combine precise addressTaken and VisibleToRegularObj, it seems that we can use this condition to decide whether ENDBR is needed with an appropriate code model:

F.hasAddressTaken() || (!F.hasLocalLinkage() && (VisibleToRegularObj || !F.hasHiddenVisibility()))

(For AArch64, even an local linkage symbol may be reached by a range extension thunk. For x86-64 we can rule out range extension thunks, but there is a caution, as internally I know a pending direction to explore that uses range extension thunks even for small code model to decrease relocation overflow pressure.)

Then we don't even need another compiler option like -mibt-seal. The Linux kernel Makefile uses -fvisibility=hidden for Clang LTO. I think it can use -fvisibility=hidden for non-LTO as well, if it doesn't have dynamic linking semantics.

After all, the option just expresses a no-dynamic-linking semantics, and this is satisfied with -fvisibility=hidden (and the guarantee that there is no undefined symbol, which I assume is satisfied)

Is https://reviews.llvm.org/D142163 a blocker for this?

Yes, and this patch needs to be updated to take VisibleToRegularObj into account. I'll update this patch once we figure out how the export symbol list for relocatable links should work.

The test is for x86, does this also work for aarch64 with BTI?

The test is for x86, does this also work for aarch64 with BTI?

IBT/BTI doesn't affect this specific optimization, it's only about KCFI. If you're referring to ibt-seal, I assume a similar optimization could be added for BTI too.

If you're referring to ibt-seal, I assume a similar optimization could be added for BTI too.

Yes, please. Does it make sense to add to this patch, or a follow up on top?

If you're referring to ibt-seal, I assume a similar optimization could be added for BTI too.

Yes, please. Does it make sense to add to this patch, or a follow up on top?

I would keep these separate. Note that ibt-seal was also reverted for now and @joaomoreira is working on fixing the issues there.

ah, sorry, I think I might be conflating "kcfi-seal" with "ibt-seal?"

Don't drop type hashes from VisibleToRegularObj symbols.

This revision is now accepted and ready to land.Feb 3 2023, 3:21 PM
nickdesaulniers accepted this revision.Feb 6 2023, 9:28 AM