Can clang's libFuzzer test more than 1 API in the same binary?

356 Views Asked by At

libFuzzer's documentation gives an example of how you would fuzz an API:

#include <stdint.h>
#include <stddef.h>

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  if (size > 0 && data[0] == 'H')
    if (size > 1 && data[1] == 'I')
       if (size > 2 && data[2] == '!')
       __builtin_trap();
  return 0;
}

I have APIs that take in single instances of different c++ types. I test the following way:

#include <stdint.h>
#include <stddef.h>
#include "my_api.hh"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  auto t = safe_deserialize<MyType>(data,size);
  my_api(t); 
  return 0;
}

The problem is, if I want to test 10 APIs, I'm left creating 10 separate binaries. I would like a single binary that is more akin to a set of unit tests. Something like this:

#include <stdint.h>
#include <stddef.h>
#include "my_api.hh"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  auto t = safe_deserialize<MyType_1>(data,size);
  my_api_1(t); 
  return 0;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  auto t = safe_deserialize<MyType_2>(data,size);
  my_api_2(t); 
  return 0;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  auto t = safe_deserialize<MyType_3>(data,size);
  my_api_3(t); 
  return 0;
}

This doesn't work because you can't have duplicate instances of LLVMFuzzerTestOneInput.
Is there a way to use Clang's libFuzzer tooling, to test more than 1 API in the same binary?

I suppose I could create some kind of universal function that dispatches to all of the other APIs, but that's undesirable because then I would need to build a corpus that is really a collection of unrelated corpuses, and crash results will be mixed across various APIs.

1

There are 1 best solutions below

1
On

How about it? You can try this. Not sure, it will work or not.

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
      auto t1 = safe_deserialize<MyType_1>(data,size);
      auto t3 = safe_deserialize<MyType_2>(data,size);
      auto t3 = safe_deserialize<MyType_3>(data,size);

      my_api_1(t1); 
      my_api_2(t2); 
      my_api_3(t3); 
      return 0;
    }