This is an archive of the discontinued LLVM Phabricator instance.

[Darwin] Improve ASan diagnostics on arm64e with pointer auth
ClosedPublic

Authored by yln on Apr 29 2020, 2:52 PM.

Details

Summary

When reporting diagnostics from ASan's (and other sanitizer's) signal
handlers we should strip the "invalid signature" bit before printing
addresses. This makes the report less confusing and let's the user
focus on the real issue.

rdar://62615826

Diff Detail

Event Timeline

yln created this revision.Apr 29 2020, 2:52 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2020, 2:52 PM
Herald added subscribers: Restricted Project, danielkiss, kristof.beyls. · View Herald Transcript
yln marked 3 inline comments as done.
yln added inline comments.
compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
783

arm_thread_state64_ptrauth_strip would be the best tool for the job here, but we can't rely on it since only the newest SDKs define it.

812

I feel that this is not the natural place to strip addr. On the other hand, it requires the least amount of changes. I have considered these other places:

  • HandleDeadlySignal() before we create the SignalContext. I decided against it because it is defined in sanitizer_symbolizer_report.cpp (a platform-independent file).
  • SignalContext::GetAddress() in sanitizer_posix.cpp.
    • We could create Mac and Linux variants of this function , or
    • use additional #ifdefs in the _posix file.

Let me know which version you prefer.

1149

Drive-by fix to nicely align the registers printed via DUMPREGA64.

kubamracek accepted this revision.May 1 2020, 9:45 AM
This revision is now accepted and ready to land.May 1 2020, 9:45 AM
delcypher requested changes to this revision.May 1 2020, 10:57 AM
delcypher added inline comments.
compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
771

Maybe this should be?

#if  defined(__arm64e__)
#  if __has_feature(ptrauth_calls)
#    include <ptrauth.h>
#  else
#    error "Compiling for arm64e but toolchain is missing ptrauth_calls"
#  endif
#else
#  if __has_feature(ptrauth_calls)
#     # error "ptrauth_calls on a non arm64e target is not supported"
#  endif
#define ptrauth_strip(value, key) (value)
#endif

I'm not sure if this is necessary because ptrauth_calls is part of the toolchain and not the SDK. So these additional checks only make sense if the AppleClang can target arm64e without the ptrauth_calls enabled.

777

@yln Is this the right place for the change? My reading of this is that this macro gets used for the pc, fp, lr, and sp registers. I would expect the contents of the pc and lr registers to be signed but I'm not sure about the fp and sp registers.

812

It does seems a little weird to be changing addr in InitPcSpBp because the name sounds like it doesn't touch addr.

Doing it in SignalContext::GetAddress() in sanitizer_posix.cpp sounds like the right thing to do. Rather than ifdef'ing the definition of the function it might be simpler to introduce a __sanitizer::ptr_auth_strip inline function in a new header file and have SignalContext::GetAddress() unconditionally use it. This new function would just return its input where the platform doesn't do ptr auth. This has the added benefit of introducing a header file we can use from multiple translation units to do ptr auth stuff. This would hopefully mean we could keep all the ifdef'ing contained to that single header file.

What do you think? If you like this idea then it probably needs to a separate change as you'll be touching non-darwin code paths. We could land this change and have two follow up patches, one that introduces the new header file and then a second that changes sanitizer_mac.cpp to use it.

This revision now requires changes to proceed.May 1 2020, 10:57 AM
yln marked 3 inline comments as done.May 1 2020, 6:25 PM
yln added inline comments.
compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
771

Ideally, we would just #include <ptrauth.h> unconditionally. It defines the macros on all platforms. The reason it is guarded with an #ifdef is that the header is fairly new and we want to be able to build with older SDKs.

Why __has_feature(ptrauth_calls) and not __has_include(<ptrauth.h>)?
I don't have a good answer for this, but that's the pattern have seen Kuba and others use.
@kubamracek Can you explain?

777

arm_thread_state64_ptrauth_strip strips all 4 registers. For ptrauth_* operations we usually have to be careful what pointer type (code/data/process-[in]dependent) we are working with and choose the right key. strip seems to always work with key 0.
My understanding is that strip just zeroes the "signature bits", i.e., an unsigned pointer isn't changed.

812

Sounds good. As a follow-up I will create a new header that essentially does what <ptrauth.h> does: define the macros as nops on platforms without ptrauth, so we can avoid excessive #ifdefing.

delcypher accepted this revision.May 6 2020, 12:17 PM

LGTM provided we introduced the discussed header in future patches.

compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
771

@yln Well the header exists in the toolchain and that toolchain can build for multiple targets, not just arm64e. Presumably the header still is available when arm64e is not the target and that's why __has_feature(ptrauth_calls) is needed too?

812

@yln I'd prefer an inline function in the proposed header rather than a macro but we can discuss this more when you put up the patch.

This revision is now accepted and ready to land.May 6 2020, 12:17 PM
This revision was automatically updated to reflect the committed changes.
thakis added a subscriber: thakis.May 18 2020, 2:15 PM

Given that this file is in lib/clang/11.0.3/include/ptrauth.h in Xcode, are there plans to upstream ptrauth.h too?