google / sanitizers

AddressSanitizer, ThreadSanitizer, MemorySanitizer
Other
11.49k stars 1.04k forks source link

Suppressing Reports in External Libraries #1027

Open LesserBabka opened 5 years ago

LesserBabka commented 5 years ago

Using gcc 8.2.0 with -fsanitize=address -fno-omit-frame-pointer on CentOS 7.2.

I would like to suppress the following error in an external library, however I haven't managed to do so.

==114064==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffe60fee2f0 at pc 0x000001e6ef34 bp 0x7ffe60feb6c0 sp 0x7ffe60feb6b8
WRITE of size 8 at 0x7ffe60fee2f0 thread T0
    #0 0x1e6ef33 in std::_Function_base::_Function_base() /opt/gcc-8.2.0/include/c++/8.2.0/bits/std_function.h:252
    #1 0x1e6ef33 in function<Engine::Engine(const Resource&, SourceDataVersion, Engine::CalculationResolution)::<lambda(std::unique_ptr<const model::Car>)> > /opt/gcc-8.2.0/include/c++/8.2.0/bits/std_function.h:668
    #2 0x1e6ef33 in Engine::Engine(esp::Resource<boost::shared_ptr<Ball const>, (esp::NotifyBehavior)0> const&, SourceDataVersion, Engine::CalculationResolution) /var/lib/jenkins/workspace/BUILD/lib/model/Engine.cpp:758
    #3 0x18725df in GaussEngine::GaussianEngine(esp::Resource<boost::shared_ptr<Ball const>, (esp::NotifyBehavior)0> const&, Engine::CalculationResolution, double, double, bool) /var/lib/jenkins/workspace/rpmbuilddir/BUILD/test/testutil/GaussEngine.cpp:40
    #4 0x1873420 in GaussEngine::GaussEngine(Engine::CalculationResolution, double, double, bool) /var/lib/jenkins/workspace/rpmbuilddir/BUILD/test/testutil/GaussEngine.cpp:30
    #5 0x188edb3 in testutil::createGaussEngine(Engine::CalculationResolution) /var/lib/jenkins/workspace/rpmbuilddir/BUILD/test/testutil/testUtil.cpp:287
    ...

I have set ASAN_OPTIONS=suppressions=MyASan.supp, with MyASan.supp containing interceptor_via_fun:_Function_base or interceptor_via_fun:*_Function_base*

But it still gives the same error and aborts the execution.

I have also tried suppressing it by using __attribute__((no_sanitize("address"))) or -fsanitize-blacklist=path with the function createGaussEngine further down the call stack which is in my code base, but I just cannot get rid of this error.

I posted a question on SO last week, but have not received any answers and googling "AddressSanitizer interceptor_via_fun" returned only 151 results, none of which have helped me resolve this.

Either suppression in external libraies does not work, or the doxumentation should be calrified on how to do this.

MetalInMyVeins commented 2 years ago

3 years old post but still no one cares about it. sad

OfekShilon commented 2 years ago

Same, on clang-14.

Enna1 commented 2 years ago

Same, on clang-14.

@OfekShilon Hi, can you provide a minimal reproducible example?

OfekShilon commented 2 years ago

@OfekShilon Hi, can you provide a minimal reproducible example?

Our case turned out to be a sort-of known false positive: a 3rd party (not instrumented with ASAN) library called back into our own library (built with ASAN). I tried to exclude the 3rd party lib via interceptor_via_lib or interceptor_via_fun (with lots of syntax variations) and failed. Exporting ASAN_OPTIONS=detect_container_overflow=0 did work.

Anyway, it is a complex setup and hard to compress into a toy repro. Is the ASAN_OPTIONS=suppressions file mechanism operational? It seems many people are having trouble getting it to work.

Enna1 commented 2 years ago

Is the ASAN_OPTIONS=suppressions file mechanism operational?

AFAIK, Yes. But It may not work the way as you expected.

Given an example:

#include <string.h>
#include <stdlib.h>

void bad_foo() {
  char *hello = (char*)malloc(6);
  strcpy(hello, "hello");
  char *short_buffer = (char*)malloc(9);
  strncpy(short_buffer, hello, 10);  // BOOM
  free(hello);
  free(short_buffer);
}

void bad_bar()
{
  int *a = (int*)malloc(40);
  free(a);
  a[1] = 1;
}

int main(int argc, char **argv) {
  bad_foo();
  bad_bar();
  return 0;
}

Above code has two bugs: heap-buffer-overflow triggered by strncpy in bad_foo, and heap-use-after-free in bad_bar. And we create a suppression file(say, mysupp.txt) containing :

interceptor_via_fun:bad_foo
interceptor_via_fun:bad_bar

Compile the above example and run with ASAN_OPTIONS=suppressions:

$ clang++ -O1 -g -fno-omit-frame-pointer -fno-builtin -fsanitize=address ./test-asan-supp.cpp -o test-asan-supp
$ ASAN_OPTIONS="suppressions=mysupp.txt" ./test-asan-supp

And you will get a heap-use-after-free in bad_bar.

Why heap-buffer-overflow in bad_foo is suppressed, but heap-use-after-free in bar_bar is not ? This is because the mechanism behind interceptor_via_fun or interceptor_via_lib. interceptor_via_fun only suppresses bug which is triggered by interceptors (e.g. strncpy, memcpy)

In above example, heap-buffer-overflow in bad_foo is triggered by strncpy, which is intercepted, so this heap-buffer-overflow in bad_foo is suppressed. heap-use-after-free in bad_bar is triggered by a[1] = 1, which is not triggered by an interceptor, so even if we have interceptor_via_fun:bad_bar in suppression list, the heap-use-after-free in bad_bar is not suppressed.

This is my understand of how suppression works, hope this will help you.

bruno-kakele commented 8 months ago

This is my understand of how suppression works, hope this will help you.

Thanks for explaining, it makes sense! Is there any other way to suppress bad_bar?

fwyzard commented 2 months ago

Thanks for explaining, it makes sense! Is there any other way to suppress bad_bar?

https://clang.llvm.org/docs/SanitizerSpecialCaseList.html suggests that a different suppression file can be passed to -fsanitize-ignorelist at compile time.