This is an archive of the discontinued LLVM Phabricator instance.

Allow -fsanitize=function on all targets
ClosedPublic

Authored by MaskRay on Apr 17 2023, 2:36 PM.

Details

Summary

Functions instrumented with -fsanitize=function have two words before
the function label: a signature and a RTTI proxy.
Instrumented call sites check the signature first to skip checks
for uninstrumented callees.

The code is generic and works for all targets supporting C++ RTTI.
Change clangDriver to allow all targets. Add tests for Armv8.5
Branch Target Identification and -fpatchable-function-entry=.

Diff Detail

Event Timeline

MaskRay created this revision.Apr 17 2023, 2:36 PM
MaskRay requested review of this revision.Apr 17 2023, 2:36 PM
Herald added projects: Restricted Project, Restricted Project, Restricted Project. · View Herald TranscriptApr 17 2023, 2:36 PM
Herald added subscribers: llvm-commits, Restricted Project, cfe-commits. · View Herald Transcript
MaskRay edited the summary of this revision. (Show Details)Apr 17 2023, 2:47 PM
MaskRay edited the summary of this revision. (Show Details)

As it stands I think this may have problems with -mbranch-protection. In that case we'll need a BTI c to be the target of the indirect branch. I'm guessing something like:

_Z3funv
BTI C ; In hint space
B . + 8 
.word .L__llvm_rtti_proxy-_Z3funv

Otherwise when the indirect call is made then it will fail on a system with BTI enabled.

Not too sure how much of a problem this is for the implementation. The BTI c can't be used as a signature, I guess the code in the caller could check the value at _z3funv + 4 . The feature could be marked as incompatible with -mbranch-protection. I guess it may not work well with patchable functions either.

I would expect the emitGlobalConstant to emit data. This would be visible in the object file as we'd have:

$d
<signature>
<rtti>
$x
instructions.

At the moment I don't think that this would affect anything except disassemblers, and the LLD cortex-a53 eratta work around which excludes $d from the disassembly. It is something that it could be worth fixing, expecially if there is a BTI C involved.

One other small thing. The docs page https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html would need the supported architectures updating:

-fsanitize=function: Indirect call of a function through a function pointer of the wrong type (Darwin/Linux, C++ and x86/x86_64 only).

As it stands I think this may have problems with -mbranch-protection. In that case we'll need a BTI c to be the target of the indirect branch. I'm guessing something like:

_Z3funv
BTI C ; In hint space
B . + 8 
.word .L__llvm_rtti_proxy-_Z3funv

Otherwise when the indirect call is made then it will fail on a system with BTI enabled.

Not too sure how much of a problem this is for the implementation. The BTI c can't be used as a signature, I guess the code in the caller could check the value at _z3funv + 4 . The feature could be marked as incompatible with -mbranch-protection. I guess it may not work well with patchable functions either.

I would expect the emitGlobalConstant to emit data. This would be visible in the object file as we'd have:

$d
<signature>
<rtti>
$x
instructions.

At the moment I don't think that this would affect anything except disassemblers, and the LLD cortex-a53 eratta work around which excludes $d from the disassembly. It is something that it could be worth fixing, expecially if there is a BTI C involved.

Thanks. I forgot to check this interaction with -mbranch-protection=bti. x86 -fcf-protection=branch has a similar problem.

The current AArch64 bti instrumentation always adds a bti (even for local linkage functions that are not taken addresses) to accommodate range extension thunks, but I can think of possible improvement to make bti optional in more cases in the future.

I think -fsanitize=function has to do something similar to -fsanitize=kcfi by moving the two words before the function entry: D148665

MaskRay updated this revision to Diff 514768.Apr 18 2023, 3:37 PM
MaskRay edited the summary of this revision. (Show Details)

Make -mbranch-protection=bti -fsanitize=function work.

peter.smith accepted this revision.Apr 19 2023, 6:36 AM

With moving the signature before the function entry this looks good to me. I'm not so familiar with the code in https://reviews.llvm.org/D148665 would ideally find someone a bit more experienced to take a look at that part. If I'm the only one available I can take a look but may take a bit more time.

We're looking to clarify when a BTI is required in the ABI https://github.com/ARM-software/abi-aa/issues/196 starting with some design options.

This revision is now accepted and ready to land.Apr 19 2023, 6:36 AM

With moving the signature before the function entry this looks good to me. I'm not so familiar with the code in https://reviews.llvm.org/D148665 would ideally find someone a bit more experienced to take a look at that part. If I'm the only one available I can take a look but may take a bit more time.

We're looking to clarify when a BTI is required in the ABI https://github.com/ARM-software/abi-aa/issues/196 starting with some design options.

Thank you!

For folks curious about -fsanitize=function, I added some paragraphs to https://maskray.me/blog/2022-12-18-control-flow-integrity#fsanitizefunction

MaskRay updated this revision to Diff 515161.Apr 19 2023, 5:55 PM
MaskRay retitled this revision from Port -fsanitize=function to AArch64 to Allow -fsanitize=function on all targets.
MaskRay edited the summary of this revision. (Show Details)

allow all targets

This revision was landed with ongoing or failed builds.May 19 2023, 7:59 AM
This revision was automatically updated to reflect the committed changes.

The ppc64le has other unrelated failures.

The aarch64 android bot failed due to being unable to link the executable, which seems an infrastructure issue? :) I think we can disable the test by modifying compiler-rt/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg.py

sbc100 added a subscriber: sbc100.May 22 2023, 10:12 AM

This change seems to be causing problems on the emscripten auto-roller: https://ci.chromium.org/ui/p/emscripten-releases/builders/try/linux/b8780394114149321217/overview

Failures show up in ubsan tests and look like this:

error: symbol '_Z4testi' unsupported subtraction expression used in relocation in code section.
error: symbol '__main_argc_argv' unsupported subtraction expression used in relocation in code section.
fatal error: error in backend: function sections must contain one function each

It seems like enabling this sanitizer perhaps uses features we don't yet support? I will keep investigating but perhaps we can find a way to revert he effect on the wasm backend for now?

(I guess this also mean we are lacking some upstream testing for ubsan + wasm + mc?)

This change seems to be causing problems on the emscripten auto-roller: https://ci.chromium.org/ui/p/emscripten-releases/builders/try/linux/b8780394114149321217/overview

Failures show up in ubsan tests and look like this:

error: symbol '_Z4testi' unsupported subtraction expression used in relocation in code section.
error: symbol '__main_argc_argv' unsupported subtraction expression used in relocation in code section.
fatal error: error in backend: function sections must contain one function each

It seems like enabling this sanitizer perhaps uses features we don't yet support? I will keep investigating but perhaps we can find a way to revert he effect on the wasm backend for now?

wasm seems to use -fsanitize=undefined, which includes -fsanitize=function.
wasm doesn't allow data words before the function entry, so we need to unsupport -fsanitize=function for wasm...

This change seems to be causing problems on the emscripten auto-roller: https://ci.chromium.org/ui/p/emscripten-releases/builders/try/linux/b8780394114149321217/overview

Failures show up in ubsan tests and look like this:

error: symbol '_Z4testi' unsupported subtraction expression used in relocation in code section.
error: symbol '__main_argc_argv' unsupported subtraction expression used in relocation in code section.
fatal error: error in backend: function sections must contain one function each

It seems like enabling this sanitizer perhaps uses features we don't yet support? I will keep investigating but perhaps we can find a way to revert he effect on the wasm backend for now?

wasm seems to use -fsanitize=undefined, which includes -fsanitize=function.
wasm doesn't allow data words before the function entry, so we need to unsupport -fsanitize=function for wasm...

That makes sense to me. The wasm specification (and therefore the wasm runtimes) already enforce signature checking for indirect function calls so there should be no need for this sanitizer there anyway. Do you want to make that change or should I?

This change seems to be causing problems on the emscripten auto-roller: https://ci.chromium.org/ui/p/emscripten-releases/builders/try/linux/b8780394114149321217/overview

Failures show up in ubsan tests and look like this:

error: symbol '_Z4testi' unsupported subtraction expression used in relocation in code section.
error: symbol '__main_argc_argv' unsupported subtraction expression used in relocation in code section.
fatal error: error in backend: function sections must contain one function each

It seems like enabling this sanitizer perhaps uses features we don't yet support? I will keep investigating but perhaps we can find a way to revert he effect on the wasm backend for now?

wasm seems to use -fsanitize=undefined, which includes -fsanitize=function.
wasm doesn't allow data words before the function entry, so we need to unsupport -fsanitize=function for wasm...

That makes sense to me. The wasm specification (and therefore the wasm runtimes) already enforce signature checking for indirect function calls so there should be no need for this sanitizer there anyway. Do you want to make that change or should I?

Thanks for the additional context (and I shall learn about it). Having been done in 39ba913d13ab15c76cb6b5aa066fa111ddfe944b