This is a segmentation fault in INTERCEPTOR function on a special edge
case of strstr libc call. When 'Haystack'(main string to be examined) is
NULL and 'needle'(sub-string to be searched in 'Haystack') is an empty
string then it hits a SEGV while using sanitizers and as a 'string not
found' case otherwise.
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D115919
The added test demonstrates loading a dynamic library with static TLS.
Such static TLS is a hack that allows a dynamic library to have faster TLS,
but it can be loaded only iff all threads happened to allocate some excess
of static TLS space for whatever reason. If it's not the case loading fails with:
dlopen: cannot load any more object with static TLS
We used to produce a false positive because dlopen will write into TLS
of all existing threads to initialize/zero TLS region for the loaded library.
And this appears to be racing with initialization of TLS in the thread
since we model a write into the whole static TLS region (we don't what part
of it is currently unused):
WARNING: ThreadSanitizer: data race (pid=2317365)
Write of size 1 at 0x7f1fa9bfcdd7 by main thread:
0 memset
1 init_one_static_tls
2 __pthread_init_static_tls
[[ this is where main calls dlopen ]]
3 main
Previous write of size 8 at 0x7f1fa9bfcdd0 by thread T1:
0 __tsan_tls_initialization
Fix this by ignoring accesses during dlopen.
Reviewed By: melver
Differential Revision: https://reviews.llvm.org/D114953
Read each pointer in the argv and envp arrays before dereferencing
it; this correctly marks an error when these pointers point into
memory that has been freed.
Differential Revision: https://reviews.llvm.org/D113046
In reviews.llvm.org/D108316 I missed a few instances of REAL(strlen) and
this change fixes that, as well as restoring one that seems like it
shouldn't have been changed.
Reviewed By: hctim, vitalybuka
Differential Revision: https://reviews.llvm.org/D108843
qsort can reuse qsort_r if available.
bsearch always passes key as the first comparator argument, so we
can use it to wrap the original comparator.
Differential Revision: https://reviews.llvm.org/D108751
Breaks realpath(, nullptr) for all sanitizers.
Somehow INTERCEPT_FUNCTION and INTERCEPT_FUNCTION_VER return
false even if everything seemingly right.
And this is the issue for COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN.
There is a check in every sanitlizer:
if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name))
For non-versioned interceptors when INTERCEPT_FUNCTION returns false
it's not considered fatal, and it just prints a warning.
However INTERCEPT_FUNCTION_VER in this case will fallback to
INTERCEPT_FUNCTION replacing realpath with wrong version.
We need to investigate that before relanding the patch.
This reverts commit faef0d042f.
Handle the case of wordexp being invoked with WRDE_DOOFFS and
we.we_offs set to a positive value, which will result in NULL
entries prepended to the result. With this change the entire
result, containing both NULL and actual entries, is unpoisoned.
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D108646
llvm-libc is expected to be built with sanitizers and not use interceptors in
the long run. For now though, we have a hybrid process, where functions
implemented in llvm-libc are instrumented, and glibc fills and sanitizer
interceptors fill in the rest.
Current sanitizers have an invariant that the REAL(...) function called from
inside of an interceptor is uninstrumented. A lot of interceptors call strlen()
in order to figure out the size of the region to check/poison. Switch these
callsites over to the internal, unsanitized implementation.
Reviewed By: hctim, vitalybuka
Differential Revision: https://reviews.llvm.org/D108316
tsan in some cases (e.g. after fork from multithreaded program, which arguably is problematic) increments ignore_interceptors and in that case runs just the intercepted functions and not their wrappers.
For realpath the interceptor handles the resolved_path == nullptr case though and so when ignore_interceptors is non-zero, realpath (".", nullptr) will fail instead of succeeding.
This patch uses instead the COMMON_INTERCEPT_FUNCTION_GLIBC_VER_MIN macro to use realpath@@GLIBC_2.3 whenever possible (if not, then it is likely a glibc architecture
with more recent oldest symbol version than 2.3, for which any realpath in glibc will DTRT, or unsupported glibc older than 2.3), which never supported NULL as second argument.
Reviewed By: dvyukov
Differential Revision: https://reviews.llvm.org/D107819
Similar to qsort, bsearch can be called from non-instrumented
code of glibc. When it happends tls for arguments can be in uninitialized
state.
Unlike to qsort, bsearch does not move data, so we don't need to
check or initialize searched memory or key. Intrumented comparator will
do that on it's own.
Differential Revision: https://reviews.llvm.org/D107387
This was fixed in the past for `frexp`, but was not made for `frexpl` & `frexpf` https://github.com/google/sanitizers/issues/321
This patch copies the fix over to `frexpl` because it caused `frexp_interceptor.cpp` test to fail on iPhone and `frexpf` for consistency.
rdar://79652161
Reviewed By: delcypher, vitalybuka
Differential Revision: https://reviews.llvm.org/D104948
Reuse the assembly glue code from sanitizer_common_interceptors.inc and
the handling logic from the __tls_get_addr interceptor.
Reviewed By: dvyukov
Differential Revision: https://reviews.llvm.org/D105629
The memcpy interceptor is the only one that uses COMMON_INTERCEPTOR_ENTER
more than once in a single function. This does not allow COMMON_INTERCEPTOR_ENTER
to use labels, because they are global for the whole function (not block scoped).
Don't include COMMON_INTERCEPTOR_ENTER code twice.
Reviewed By: melver
Differential Revision: https://reviews.llvm.org/D105774
sem_trywait never blocks.
Use REAL instead of COMMON_INTERCEPTOR_BLOCK_REAL.
Reviewed By: melver
Differential Revision: https://reviews.llvm.org/D105775
setlocale interceptor imitates a write into result,
which may be located in .rodata section.
This is the only interceptor that tries to do this and
I think the intention was to initialize the range for msan.
So do that instead. Writing into .rodata shouldn't happen
(without crashing later on the actual write) and this
traps on my local tsan experiments.
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D102161
Previously, on GLibc systems, the interceptor was calling __compat_regexec
(regexec@GLIBC_2.2.5) insead of the newer __regexec (regexec@GLIBC_2.3.4).
The __compat_regexec strips the REG_STARTEND flag but does not report an
error if other flags are present. This can result in infinite loops for
programs that use REG_STARTEND to find all matches inside a buffer (since
ignoring REG_STARTEND means that the search always starts from the first
character).
The underlying issue is that GLibc's dlsym(RTLD_NEXT, ...) appears to
always return the oldest versioned symbol instead of the default. This
means it does not match the behaviour of dlsym(RTLD_DEFAULT, ...) or the
behaviour documented in the manpage.
It appears a similar issue was encountered with realpath and worked around
in 77ef78a0a5.
See also https://sourceware.org/bugzilla/show_bug.cgi?id=14932 and
https://sourceware.org/bugzilla/show_bug.cgi?id=1319.
Fixes https://github.com/google/sanitizers/issues/1371
Reviewed By: #sanitizers, vitalybuka, marxin
Differential Revision: https://reviews.llvm.org/D96348
The hackery is due to glibc clock_gettime crashing from preinit_array (D40679).
32-bit musl architectures do not define `__NR_clock_gettime` so the code causes a compile error.
Tested on Alpine Linux x86-64 (musl) and FreeBSD x86-64.
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D96925
Also unpoison IO_write_base/_IO_write_end buffer
memcpy from fclose and fflash can copy internal bytes without metadata into user memory.
Reviewed By: eugenis
Differential Revision: https://reviews.llvm.org/D91858
- Fixing VS compiler and other cases settings this time.
Reviewers: dmajor, hans
Reviewed By: hans
Differential Revision: https://reviews.llvm.org/D89759
Revert "Fix compiler-rt build on Windows after D89640"
This reverts commit a7acee89d6.
This reverts commit d09b08919c.
Reason: breaks Linux / x86_64 build.
Can be used to disable interceptor to workaround issues of
non-instrumented code.
Reviewed By: morehouse, eugenis
Differential Revision: https://reviews.llvm.org/D87897
When the FreeBSD qsort() implementation recurses, it does so using an
interposable function call, so we end up calling the interceptor again
and set the saved comparator to wrapped_qsort_compar. This results in an
infinite loop and a eventually a stack overflow since wrapped_qsort_compar
ends up calling itself. This means that ASAN is completely broken on
FreeBSD for programs that call qsort(). I found this while running
check-all on a FreeBSD system a ASAN-instrumented LLVM.
Fix this by checking whether we are recursing inside qsort before writing
to qsort_compar. The same bug exists in the qsort_r interceptor, so use the
same approach there. I did not test the latter since the qsort_r function
signature does not match and therefore it's not intercepted on FreeBSD/macOS.
Fixes https://llvm.org/PR46832
Reviewed By: eugenis
Differential Revision: https://reviews.llvm.org/D84509
For now, xdrrec_create is only intercepted Linux as its signature
is different on Solaris.
The method of intercepting xdrrec_create isn't super ideal but I
couldn't think of a way around it: Using an AddrHashMap combined
with wrapping the userdata field.
We can't just allocate a handle on the heap in xdrrec_create and leave
it at that, since there'd be no way to free it later. This is because it
doesn't seem to be possible to access handle from the XDR struct, which
is the only argument to xdr_destroy.
On the other hand, the callbacks don't have a way to get at the
x_private field of XDR, which is what I chose for the HashMap key. So we
need to wrap the handle parameter of the callbacks. But we can't just
pass x_private as handle (as it hasn't been set yet). We can't put the
wrapper struct into the HashMap and pass its pointer as handle, as the
key we need (x_private again) hasn't been set yet.
So I allocate the wrapper struct on the heap, pass its pointer as
handle, and put it into the HashMap so xdr_destroy can find it later and
destroy it.
Differential Revision: https://reviews.llvm.org/D83358