This is an archive of the discontinued LLVM Phabricator instance.

[clang] Do not instrument relative vtables under hwasan
ClosedPublic

Authored by leonardchan on Aug 22 2022, 5:24 PM.

Details

Summary

Full context in https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=107017.

Instrumenting hwasan with globals results in a linker error under the relative vtables abi:

ld.lld: error: libunwind.cpp:(.rodata..L_ZTVN9libunwind12UnwindCursorINS_17LocalAddressSpaceENS_15Registers_arm64EEE.hwasan+0x8): relocation R_AARCH64_PLT32 out of range: 6845471433603167792 is not in [-2147483648, 2147483647]; references libunwind::AbstractUnwindCursor::~AbstractUnwindCursor()
>>> defined in libunwind/src/CMakeFiles/unwind_shared.dir/libunwind.cpp.obj

This is because the tag is included in the vtable address when calculating the offset between the vtable and virtual function. A temporary solution until we can resolve this is to just disable hwasan instrumentation on relative vtables specifically, which can be done in the frontend.

Diff Detail

Event Timeline

leonardchan created this revision.Aug 22 2022, 5:24 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 22 2022, 5:24 PM
leonardchan requested review of this revision.Aug 22 2022, 5:24 PM
leonardchan edited the summary of this revision. (Show Details)
mcgrathr accepted this revision.Aug 23 2022, 11:22 AM

lgtm.
You might add some comments in CGVTables.cpp about why this is done and what the alternatives might be in the future.

This revision is now accepted and ready to land.Aug 23 2022, 11:22 AM

lgtm.
You might add some comments in CGVTables.cpp about why this is done and what the alternatives might be in the future.

Done.

Glad to see that refactoring the sanitizer metadata made someone's life easier ;) (now allowing for disabling hwasanificiation of globals)

Patch looks reasonable to me. Can you please add the negative test (that vtables under the vanilla ABI still have hwasan)?

I wans't fully aware of the relative vtables ABI, and it may have some implications about MTE globals tagging (draft abi). Because logical tags are synthesized at runtime into a synthetic GOT entry - dynamic relocations I believe would be forced (removing any benefit of the relative vtables ABI), so for now it seems like MTE globals and relative vtables are mutually exclusive. Another option would be to disable MTE globals for relative vtables as well. No action needed on your part, just putting some wordso n paper that this might need some consideration at a later date if Fuchsia wants to support MTE globals.

clang/test/CodeGenCXX/RelativeVTablesABI/relative-vtables-hwasan.cpp
2

Can you add a note here that -triple=aarch64-unknown-fuchsia has implicit relative vtables

Glad to see that refactoring the sanitizer metadata made someone's life easier ;) (now allowing for disabling hwasanificiation of globals)

Patch looks reasonable to me. Can you please add the negative test (that vtables under the vanilla ABI still have hwasan)?

Yup. Will add a followup patch.

I wans't fully aware of the relative vtables ABI, and it may have some implications about MTE globals tagging (draft abi). Because logical tags are synthesized at runtime into a synthetic GOT entry - dynamic relocations I believe would be forced (removing any benefit of the relative vtables ABI), so for now it seems like MTE globals and relative vtables are mutually exclusive. Another option would be to disable MTE globals for relative vtables as well. No action needed on your part, just putting some wordso n paper that this might need some consideration at a later date if Fuchsia wants to support MTE globals.

Thanks for bringing this up. For relative vtables, the important bit is that the vtable is populated with statically known offsets between the vtable and its virtual functions. The particular linker error this patch resolves occurs because the hwasan pass happens to replace references to the vtable (within the vtable) with the alias, so the tag causes an overflow when resolving the relocation.

Now if I'm understanding the draft correctly, the way MTE will work with globals is that all references to globals *must* go through the GOT because the dynamic linker will place the tagged address there, so the potential conflict with relative vtables is that we wouldn't know the full tagged address of the vtable at link time, hence the dynamic relocation. If so, simply disabling MTE on relative vtables would also be a short term solution.

We have a generic long term solution for hwasan+RV which I think might also be applicable for MTE+RV. For hwasan, since it's mainly the IR pass that converts usages of the vtable (within the vtable itself) to use tagged aliases, the ideal solution is to just have hwasan ignore these specific references in the vtable such that offset calculation can continue to use the untagged address allowing the relocation arithmetic to not overflow. Now for llvm, I'm assuming it's an instrumentation pass like memtagsanitizer that will ensure all references to globals go through the GOT by replacing all global references with the appropriate IR that gets lowered to this GOT reference. If this is the case, then I *think* a similar solution can be done here where particular references to the vtable continue to use the original vtable address and avoid instrumentation.

hctim added a comment.Aug 26 2022, 5:39 PM

We have a generic long term solution for hwasan+RV which I think might also be applicable for MTE+RV. For hwasan, since it's mainly the IR pass that converts usages of the vtable (within the vtable itself) to use tagged aliases, the ideal solution is to just have hwasan ignore these specific references in the vtable such that offset calculation can continue to use the untagged address allowing the relocation arithmetic to not overflow. Now for llvm, I'm assuming it's an instrumentation pass like memtagsanitizer that will ensure all references to globals go through the GOT by replacing all global references with the appropriate IR that gets lowered to this GOT reference. If this is the case, then I *think* a similar solution can be done here where particular references to the vtable continue to use the original vtable address and avoid instrumentation.

HWASan and MTE have a nice invariant that helps - functions aren't tagged (phew). IIUC, For HWASan, it seems like you could just use an _NC relocation and truncate off the tag bits when materializing a function pointer from the relative vtable. For MTE, taking the address of the vtable would be indirect (as it has to be grabbed from the GOT), and applying the offset would result in a tagged function pointer. Because code pages aren't mapped as PROT_MTE, seems like this would succeed (maybe unwinders would have to be taught to truncate any tag bits, but that seems about it).

Either way, I don't think we should worry about it right this instant, and any problems would be easily detected during experimentation.

Didn't actually realise this was submitted. Appreciate the follow-up patch for non-relative-vtables + hwasan :).