Skip to content

Add support for recognizing crashes in native extensions #737

@PaDarochek

Description

@PaDarochek

Description

I tried to apply Jazzer.js to fuzzing JS code extended with C++ code. C++ code was binded to JS code via Napi and was instrumented with sanitizers (e.g. ASan). I've found out that even if reports from sanitizers are displayed, these crashes are not considered to be crashes and are not saved to any files.

Screenshot from 2023-12-26 16-54-10
Screenshot from 2023-12-26 16-54-27

Could you please support recognizing these crashes the same way as JS crashes?

Steps to reproduce

  • Create fuzz target (native_fuzzer.js) from the code:
    #!/usr/bin/env -S npx jazzer
    
    const native_lib = require('bindings')('native')
    
    function fuzz(data) {
        if (data[0] > 'x') {
            native_lib.foo(5);
        } else if (data[1] > 'x') {
            native_lib.foo(2);
        }
    }
    
    module.exports.fuzz = function (data /*: Buffer */) {
        const fuzzerData = data.toString();
        fuzz(fuzzerData);
    };
  • Create native library file:
    #include <napi.h>
    #include <stdio.h>
    
    void
    foo(const Napi::CallbackInfo& info)
    {
        Napi::Env env = info.Env();
        if (info.Length() < 1)
        {
            Napi::TypeError::New(env, "Wrong number of arguments")
                .ThrowAsJavaScriptException();
        }
        if (!info[0].IsNumber())
        {
            Napi::TypeError::New(env, "Wrong arguments")
                .ThrowAsJavaScriptException();
        }
        uint32_t idx = info[0].As<Napi::Number>().Uint32Value();
    
        uint8_t buf[] = {1, 2, 3};
        Napi::Buffer<uint8_t> arr = Napi::Buffer<uint8_t>::New(env, &buf[0], 3);
    
        arr[idx] = 1;
        printf("Number: %u\n", arr[idx]);
    }
    
    Napi::Object
    init(Napi::Env env, Napi::Object exports)
    {
        exports.Set(Napi::String::New(env, "foo"), Napi::Function::New(env, foo));
        return exports;
    };
    
    NODE_API_MODULE(native, init);
  • Create binding file:
    {
        "targets": [
            {
                "cflags": [ "-fexceptions -fsanitize=address,fuzzer-no-link,undefined -O0 -g -fPIC" ],
                "cflags_cc": [ "-fexceptions -fsanitize=address,fuzzer-no-link,undefined -O0 -g -fPIC" ],
                "include_dirs" : ["<!@(node -p \"require('node-addon-api').include\")"],
                "target_name": "native",
                "sources": [ "native.cpp" ],
                'defines': [ 'NAPI_CPP_EXCEPTIONS' ]
            }
        ]
    }
  • Install required packages and build fuzz target in the current directory:
    CC=clang CXX=clang++ npm init -y
    npm install node-addon-api bindings
    CC=clang CXX=clang++ node install .
  • Launch Jazzer.js with the following arguments:
      ASAN_OPTIONS="abort_on_error=1,allocator_may_return_null=1,detect_leaks=0,hard_rss_limit_mb=0,malloc_context_size=0" LD_PRELOAD="$(clang++ -print-file-name=libclang_rt.asan-x86_64.so)" ./native_fuzzer.js ./corpus -- -artifact_prefix=./crashes/ -use_value_profile=1 -verbosity=2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions