A dozen 32-bit `AddressSanitizer` testcases FAIL on the latest beta of Solaris 11.4/x86, e.g.
`AddressSanitizer-i386-sunos :: TestCases/null_deref.cpp` produces
AddressSanitizer:DEADLYSIGNAL
=================================================================
==29274==ERROR: AddressSanitizer: stack-overflow on address 0x00000028 (pc 0x08135efd bp 0xfeffdfd8 sp 0x00000000 T0)
#0 0x8135efd in NullDeref(int*) /vol/llvm/src/llvm-project/dist/compiler-rt/test/asan/TestCases/null_deref.cpp:15:10
#1 0x8135ea6 in main /vol/llvm/src/llvm-project/dist/compiler-rt/test/asan/TestCases/null_deref.cpp:21:3
#2 0x8084b85 in _start (null_deref.cpp.tmp+0x8084b85)
SUMMARY: AddressSanitizer: stack-overflow /vol/llvm/src/llvm-project/dist/compiler-rt/test/asan/TestCases/null_deref.cpp:15:10 in NullDeref(int*)
==29274==ABORTING
instead of the expected
AddressSanitizer:DEADLYSIGNAL
=================================================================
==29276==ERROR: AddressSanitizer: SEGV on unknown address 0x00000028 (pc 0x08135f1f bp 0xfeffdf48 sp 0xfeffdf40 T0)
==29276==The signal is caused by a WRITE memory access.
==29276==Hint: address points to the zero page.
#0 0x8135f1f in NullDeref(int*) /vol/llvm/src/llvm-project/local/compiler-rt/test/asan/TestCases/null_deref.cpp:15:10
#1 0x8135efa in main /vol/llvm/src/llvm-project/local/compiler-rt/test/asan/TestCases/null_deref.cpp:21:3
#2 0x8084be5 in _start (null_deref.cpp.tmp+0x8084be5)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /vol/llvm/src/llvm-project/local/compiler-rt/test/asan/TestCases/null_deref.cpp:15:10 in NullDeref(int*)
==29276==ABORTING
I managed to trace this to a change in `<sys/regset.h>`: previously the header would
primarily define the short register indices (like `UESP`). While they are required by the
i386 psABI, they are only required in `<ucontext.h>` and could previously leak into
unsuspecting user code, polluting the namespace and requiring elaborate workarounds
like that in `llvm/include/llvm/Support/Solaris/sys/regset.h`. The change fixed that by restricting
the definition of the short forms appropriately, at the same time defining all `REG_` prefixed
forms for compatiblity with other systems. This exposed a bug in `compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp`, however:
Previously, the index for the user stack pointer would be hardcoded if `REG_ESP`
wasn't defined. Now with that definition present, it turned out that `REG_ESP` was the wrong index to use: the previous value 17 (and `REG_SP`) corresponds to `REG_UESP`
instead.
With that change, the failures are all gone.
Tested on `amd-pc-solaris2.11`.
Differential Revision: https://reviews.llvm.org/D83664
Support macOS 11 in our runtime version checking code and update
`GetMacosAlignedVersionInternal()` accordingly. This follows the
implementation of `Triple::getMacOSXVersion()` in the Clang driver.
Reviewed By: delcypher
Differential Revision: https://reviews.llvm.org/D82918
This also allows intercepting these getprotoent functions on Linux as
well, since Linux exposes them.
Differential Revision: https://reviews.llvm.org/D82424
Summary:
28c91219c7 introduced an interceptor for `sigaltstack`. It turns out this
broke `setjmp` on i386 macOS. This is because the implementation of `setjmp` on
i386 macOS is written in assembly and makes the assumption that the call to
`sigaltstack` does not clobber any registers. Presumably that assumption was
made because it's a system call. In particular `setjmp` assumes that before
and after the call that `%ecx` will contain a pointer the `jmp_buf`. The
current interceptor breaks this assumption because it's written in C++ and
`%ecx` is not a callee-saved register. This could be fixed by writing a
trampoline interceptor to the existing interceptor in assembly that
ensures all the registers are preserved. However, this is a lot of work
for very little gain. Instead this patch just disables the interceptor
on i386 macOS.
For other Darwin architectures it currently appears to be safe to intercept
`sigaltstack` using the current implementation because:
* `setjmp` for x86_64 saves the pointer `jmp_buf` to the stack before calling `sigaltstack`.
* `setjmp` for armv7/arm64/arm64_32/arm64e appears to not call `sigaltstack` at all.
This patch should unbreak (once they are re-enabled) the following
tests:
```
AddressSanitizer-Unit :: ./Asan-i386-calls-Test/AddressSanitizer.LongJmpTest
AddressSanitizer-Unit :: ./Asan-i386-calls-Test/AddressSanitizer.SigLongJmpTest
AddressSanitizer-Unit :: ./Asan-i386-inline-Test/AddressSanitizer.LongJmpTest
AddressSanitizer-Unit :: ./Asan-i386-inline-Test/AddressSanitizer.SigLongJmpTest
AddressSanitizer-i386-darwin :: TestCases/longjmp.cpp
```
This patch introduces a `SANITIZER_I386` macro for convenience.
rdar://problem/62141412
Reviewers: kubamracek, yln, eugenis
Subscribers: kristof.beyls, #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D82691
The Swift symbol name prefix has changed from `_T0` to `_$s` as
documented here [1]. This prevents Swift names from properly being
symbolicated when using the in-process LLVM symbolizer. The best way to
fix this seems to be to avoid the duplication of "Is this a Swift symbol
name?" here. We can simply remove this check as `swift_demangle`
already returns null for non-Swift names [2,3].
The check was included in the initial support for Swift name demangling
to avoid superfluous calls to `dlsym()` [4]. A subsequent commit
changed this logic to retrieve the `swift_demangle` function pointer
eagerly during sanitizer initialization, but did not remove the check
[5].
[1] https://github.com/apple/swift/blob/master/docs/ABI/Mangling.rst
[2] b5a8b518ea/include/swift/Demangling/Demangle.h (L643)
[3] b5a8b518ea/stdlib/public/runtime/Demangle.cpp (L656)
[4] https://reviews.llvm.org/D19135
[5] https://reviews.llvm.org/D20015
rdar://62753845
Reviewers: kubamracek, delcypher, dcoughlin, samsonov, thakis
Reviewed By: kubamracek
Differential Revision: https://reviews.llvm.org/D81705
Summary:
Currently, there is no way to let the `InternalSymbolizer` implemented
functions know if inline frames should be symbolized. This patch updates
the function `__sanitizer_symbolize_code` to include a parameter for
this ASAN option and toggle between LLVM symbolization functions when
appropriate.
Fixes the following two failing tests when internal symbolization is
enabled:
```
SanitizerCommon-*-x86_64-Linux :: print-stack-trace.cpp
SanitizerCommon-*-x86_64-Linux :: symbolize_pc_inline.cpp
```
Reviewers: vitalybuka, kcc, filcab
Reviewed By: vitalybuka
Subscribers: #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D79280
Summary: Refactor the current global header iteration to be callback-based, and add a feature that reports the size of the global variable during reporting. This allows binaries without symbols to still report the size of the global variable, which is always available in the HWASan globals PT_NOTE metadata.
Reviewers: eugenis, pcc
Reviewed By: pcc
Subscribers: mgorny, llvm-commits, #sanitizers
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D80599
Use a struct to represent numerical versions instead of encoding release
names in an enumeration. This avoids the need to extend the enumeration
every time there is a new release.
Rename `GetMacosVersion() -> GetMacosAlignedVersion()` to better reflect
how this is used on non-MacOS platforms.
Reviewed By: delcypher
Differential Revision: https://reviews.llvm.org/D79970
Remove it from target-specific scope which corresponds
to sanitizer_linux.cpp where it lives in the same macro
scope.
Differential Revision: https://reviews.llvm.org/D80864
This applies the learnings from [1]. What I intended as a simple
cleanup made me realize that the compiler-rt version checks have two
separate issues:
1) In some places (e.g., mmap flag setting) what matters is the kernel
version, not the OS version.
2) OS version checks are implemented by querying the kernel version.
This is not necessarily correct inside the simulators if the
simulator runtime isn't aligned with the host macOS.
This commit tackles 1) by adopting a separate query function for the
Darwin kernel version. 2) (and cleanups) will be dealt with in
follow-ups.
[1] https://reviews.llvm.org/D78942
rdar://63031937
Reviewed By: delcypher
Differential Revision: https://reviews.llvm.org/D79965
Summary:
Fix hwasan allocator not respecting the requested alignment when it is
higher than a page, but still within primary (i.e. [2048, 65536]).
Reviewers: pcc, hctim, cryptoad
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D79656
Create a sanitizer_ptrauth.h header that #includes <ptrauth> when
available and defines just the required macros as "no ops" otherwise.
This should avoid the need for excessive #ifdef'ing.
Follow-up to and discussed in: https://reviews.llvm.org/D79132
Reviewed By: delcypher
Differential Revision: https://reviews.llvm.org/D79540
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
Reviewed By: kubamracek, delcypher
Differential Revision: https://reviews.llvm.org/D79132
Newer iOS SDK introduce accessors to retrieve the register values
(arm_thread_state64_get_*) and disallows direct access to fields. If
arm_thread_state64_get_sp is defined, the accessors are available.
Summary:
Following up the discussion on D77638 (and following rGd6cfed6060c283dc4a6bf9ca294dcd732e8b9f72
as example), defining `__sanitizer_cov_bool_flag_init` as the weak interface
functions in various compiler-rt/ files.
Reviewers: vitalybuka
Reviewed By: vitalybuka
Subscribers: dberris, #sanitizers
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D77857
Summary:
861b69faee (rdar://problem/58789439) while
fixing symbolization for TSan completely broke ASan's runtime for the
simulators.
The problem with the previous patch is that the memory passed to
`putenv()` was poisoned and when passed to `putenv()` it tripped
an interceptor for `strchr()` which saw the memory was poisoned and
raised an ASan issue.
The memory was poisoned because `AtosSymbolizerProcess` objects
are created using ASan's internal allocator. Memory from this
allocator gets poisoned with `kAsanInternalHeapMagic`.
To workaround this, this patch makes the memory for the environment
variable entry a global variable that isn't poisoned.
This pass also adds a `DCHECK(getenv(K_ATOS_ENV_VAR))` because the
following DCHECK would crash because `internal_strcmp()` doesn't
work on nullptr.
rdar://problem/62067724
Reviewers: kubamracek, yln
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D78525
Summary:
Due to sandbox restrictions in the recent versions of the simulator runtime the
atos program is no longer able to access the task port of a parent process
without additional help.
This patch fixes this by registering a task port for the parent process
before spawning atos and also tells atos to look for this by setting
a special environment variable.
This patch is based on an Apple internal fix (rdar://problem/43693565) that
unfortunately contained a bug (rdar://problem/58789439) because it used
setenv() to set the special environment variable. This is not safe because in
certain circumstances this can trigger a call to realloc() which can fail
during symbolization leading to deadlock. A test case is included that captures
this problem.
The approach used to set the necessary environment variable is as
follows:
1. Calling `putenv()` early during process init (but late enough that
malloc/realloc works) to set a dummy value for the environment variable.
2. Just before `atos` is spawned the storage for the environment
variable is modified to contain the correct PID.
A flaw with this approach is that if the application messes with the
atos environment variable (i.e. unsets it or changes it) between the
time its set and the time we need it then symbolization will fail. We
will ignore this issue for now but a `DCHECK()` is included in the patch
that documents this assumption but doesn't check it at runtime to avoid
calling `getenv()`.
The issue reported in rdar://problem/58789439 manifested as a deadlock
during symbolization in the following situation:
1. Before TSan detects an issue something outside of the runtime calls
setenv() that sets a new environment variable that wasn't previously
set. This triggers a call to malloc() to allocate a new environment
array. This uses TSan's normal user-facing allocator. LibC stores this
pointer for future use later.
2. TSan detects an issue and tries to launch the symbolizer. When we are in the
symbolizer we switch to a different (internal allocator) and then we call
setenv() to set a new environment variable. When this happen setenv() sees
that it needs to make the environment array larger and calls realloc() on the
existing enviroment array because it remembers that it previously allocated
memory for it. Calling realloc() fails here because it is being called on a
pointer its never seen before.
The included test case closely reproduces the originally reported
problem but it doesn't replicate the `((kBlockMagic)) ==
((((u64*)addr)[0])` assertion failure exactly. This is due to the way
TSan's normal allocator allocates the environment array the first time
it is allocated. In the test program addr[0] accesses an inaccessible
page and raises SIGBUS. If TSan's SIGBUS signal handler is active, the
signal is caught and symbolication is attempted again which results in
deadlock.
In the originally reported problem the pointer is successfully derefenced but
then the assert fails due to the provided pointer not coming from the active
allocator. When the assert fails TSan tries to symbolicate the stacktrace while
already being in the middle of symbolication which results in deadlock.
rdar://problem/58789439
Reviewers: kubamracek, yln
Subscribers: jfb, #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D78179
Summary:
This is implemented by adding a `Symbolizer::LateInitializeTools()`
method that iterates over the registered tools and calls the
`LateInitialize()` method on them.
`Symbolizer::LateInitializeTools()` is now called from the various
`Symbolizer::LateInitialize()` implementations.
The default implementation of `SymbolizerTool::LateInitialize()`
does nothing so this change should be NFC.
This change allows `SymbolizerTool` implementations to perform
any initialization that they need to perform at the
LateInitialize stage of a sanitizer runtime init.
rdar://problem/58789439
Reviewers: kubamracek, yln, vitalybuka, cryptoad, phosek, rnk
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D78178
Summary:
Previously `AtosSymbolizer` would set the PID to examine in the
constructor which is called early on during sanitizer init. This can
lead to incorrect behaviour in the case of a fork() because if the
symbolizer is launched in the child it will be told examine the parent
process rather than the child.
To fix this the PID is determined just before the symbolizer is
launched.
A test case is included that triggers the buggy behaviour that existed
prior to this patch. The test observes the PID that `atos` was called
on. It also examines the symbolized stacktrace. Prior to this patch
`atos` failed to symbolize the stacktrace giving output that looked
like...
```
#0 0x100fc3bb5 in __sanitizer_print_stack_trace asan_stack.cpp:86
#1 0x10490dd36 in PrintStack+0x56 (/path/to/print-stack-trace-in-code-loaded-after-fork.cpp.tmp_shared_lib.dylib:x86_64+0xd36)
#2 0x100f6f986 in main+0x4a6 (/path/to/print-stack-trace-in-code-loaded-after-fork.cpp.tmp_loader:x86_64+0x100001986)
#3 0x7fff714f1cc8 in start+0x0 (/usr/lib/system/libdyld.dylib:x86_64+0x1acc8)
```
After this patch stackframes `#1` and `#2` are fully symbolized.
This patch is also a pre-requisite refactor for rdar://problem/58789439.
Reviewers: kubamracek, yln
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D77623
Summary:
In preparation for writing a test for a bug fix we need to be able to
see the command used to launch the symbolizer process. This feature
will likely be useful for debugging how the Sanitizers use the
symbolizer in general.
This patch causes the command line used to launch the process to be
shown at verbosity level 3 and higher.
A small test case is included.
Reviewers: kubamracek, yln, vitalybuka, eugenis, kcc
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D77622
Summary:
Commit b684c1a50f ("Add a `Symbolizer::GetEnvP()` method that allows
symbolizer implementations to customise the environment of the
symbolizer binary.") exposed a latent ARM issue, and that broke
http://lab.llvm.org:8011/builders/clang-cmake-thumbv7-full-sh
This coincided with breakage caused by my commit 5f5fb56c68
("[compiler-rt] Intercept the uname() function"), so I had to
investigate.
The issue is that GetArgsAndEnv does not work on ARM: there glibc's
_start overwrites argc value stored at __libc_start_end, breaking the
existing argv/envp parsing logic.
Fix by inferring argc from argv.
Reviewers: eugenis, vitalybuka
Reviewed By: eugenis
Subscribers: dberris, kristof.beyls, danielkiss, #sanitizers, delcypher
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D77400