google / sanitizers

AddressSanitizer, ThreadSanitizer, MemorySanitizer
Other
11.33k stars 1.02k forks source link

ASAN cannot deallocate buffer used as sigaltstack #1152

Open BillyDonahue opened 4 years ago

BillyDonahue commented 4 years ago

Clang7, Ubuntu (also verified with Clang6 system clang)

I install a 1MiB buffer as sigaltstack in a new std::thread. That std::thread is cleaned up, and the 1MiB buffer is free()d.

So the buffer is no longer registered as the sigaltstack of any thread.

At the end of the program, asan complains that it cannot unmap the 1MiB buffer.

If I uninstall the sigaltstack with SS_DISABLE from the std::thread before its execution completes, then ASAN has no problem.

Here's a small repro:

$ (
CXX=/opt/mongodbtoolchain/v3/bin/clang++ ; \
uname -a && \
$CXX --version && \
cat asan_test.cpp && \
$CXX -O2 -std=c++17 -fsanitize=address  -lpthread -ldl  asan_test.cpp   -o asan_test && \
./asan_test
)

Linux billydev 4.15.0-54-generic #58-Ubuntu SMP Mon Jun 24 10:55:24 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
MongoDB clang version 7.0.0 (tags/RELEASE_700/final) (based on LLVM 7.0.0)
Target: x86_64-mongodb-linux
Thread model: posix
InstalledDir: /opt/mongodbtoolchain/v3/bin

#include <inttypes.h>
#include <stddef.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <thread>

void sigAltStackInstall(void* buf, size_t bufSize) {
    fprintf(stderr, "installing sigaltstack= @%p[%#zx]\n", buf, bufSize);
    stack_t ss;
    ss.ss_sp = buf;
    ss.ss_size = bufSize;
    ss.ss_flags = 0;
    if (int r = sigaltstack(&ss, nullptr); r < 0) {
        perror("sigaltstack");
    }
}

void sigAltStackUninstall() {
    stack_t ss;
    ss.ss_sp = 0;
    ss.ss_size = 0;
    ss.ss_flags = SS_DISABLE;
    if (int r = sigaltstack(&ss, nullptr); r < 0) {
        perror("sigaltstack");
    }
}

int main(int argc, char** argv) {
    const size_t bufSize = size_t{1} << 20;  // 1 MiB
    unsigned char* buf = (unsigned char*)malloc(bufSize);
    {
        std::thread thr([&] {
            sigAltStackInstall(buf, bufSize);
            // asan is happy if sigaltstack is uninstalled here.
            // sigAltStackUninstall();
        });
        thr.join();
    }
    free(buf);
}
installing sigaltstack= @0x7fead82ff800[0x100000]
==5126==ERROR: AddressSanitizer failed to deallocate 0x100000 (1048576) bytes at address 0x7fead82ff800
==5126==AddressSanitizer CHECK failed: /home/billy/dev/10gen/toolchain-builder/tmp/build-llvm.sh-hVu/llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc:62 "(("unable to unmap" && 0)) != (0)" (0x0, 0x0)
    #0 0x4cbaab in __asan::AsanCheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) /home/billy/dev/10gen/toolchain-builder/tmp/build-llvm.sh-hVu/llvm/projects/compiler-rt/lib/asan/asan_rtl.cc:74:5
    #1 0x4dfcbf in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) /home/billy/dev/10gen/toolchain-builder/tmp/build-llvm.sh-hVu/llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_termination.cc:79:5
    #2 0x4db10e in __sanitizer::UnmapOrDie(void*, unsigned long) /home/billy/dev/10gen/toolchain-builder/tmp/build-llvm.sh-hVu/llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc:62:5
    #3 0x4e130f in __sanitizer::UnsetAlternateSignalStack() /home/billy/dev/10gen/toolchain-builder/tmp/build-llvm.sh-hVu/llvm/projects/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc:198:3
    #4 0x4ce185 in __asan::AsanThread::Destroy() /home/billy/dev/10gen/toolchain-builder/tmp/build-llvm.sh-hVu/llvm/projects/compiler-rt/lib/asan/asan_thread.cc:105:40
    #5 0x7feadc644407 in __nptl_deallocate_tsd.part.5 (/lib/x86_64-linux-gnu/libpthread.so.0+0x6407)
    #6 0x7feadc64581a in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x781a)
    #7 0x7feadb9ac88e in clone /build/glibc-OTsEL5/glibc-2.27/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95

https://github.com/BillyDonahue/mongo-experimental/blob/master/asan-sigaltstack-dealloc/asan_test.cpp

FruitClover commented 4 years ago

Use ASAN_OPTIONS="use_sigaltstack=0" ./test if you installs your own sigaltstack.

bing-ma commented 2 years ago

We recently encountered this issue in our sanitizer-related project (Clang14 on Ubuntu 20.04). I see the status is still 'open' for this issue, does it mean that there will be a formal fix other than using ASAN_OPTIONS="use_sigaltstack=0"?

The problem of using ASAN_OPTIONS="use_sigaltstack=0", is that it cannot control sigaltstack per thread! All compiler_rt threads will have "use_sigaltstack=0" even if user app doesn't install sigaltstack for that thread!

Any comment about the future plan will be greatly appreciated, as we will use it as a guidance to plan our project which has dependency on this!