Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERROR: AddressSanitizer: heap-buffer-overflow in rapidjson::GenericStringStream<rapidjson::UTF8<char> >::Peek() const #1257

Closed
EnchantedJohn opened this issue May 15, 2018 · 6 comments

Comments

@EnchantedJohn
Copy link

hello,guys. I use libfuzzer to test simplereader example.I found a crash. I think it is due to Peek()function
rapidjson/stream.h:115:30 in rapidjson::GenericStringStream<rapidjson::UTF8 >::Peek() const.
then I want to show my example.

@EnchantedJohn
Copy link
Author

EnchantedJohn commented May 15, 2018

My fuzz example:

#include "../../include/rapidjson/reader.h"
#include

using namespace rapidjson;
using namespace std;

struct MyHandler {
bool Null() { cout << "Null()" << endl; return true; }
bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
bool RawNumber(const char* str, SizeType length, bool copy) {
cout << "Number(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
return true;
}
bool String(const char* str, SizeType length, bool copy) {
cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
return true;
}
bool StartObject() { cout << "StartObject()" << endl; return true; }
bool Key(const char* str, SizeType length, bool copy) {
cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
return true;
}
bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
bool StartArray() { cout << "StartArray()" << endl; return true; }
bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
};

extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size)
{

MyHandler handler;
Reader reader;
StringStream ss(Data);
reader.Parse(ss, handler);

    return 0;

}

@EnchantedJohn
Copy link
Author

EnchantedJohn commented May 15, 2018

then Error message:
root@yhk-RH2485-V2:/home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader# ./fuzz-reader corpus1/
INFO: Seed: 986180824
INFO: Loaded 1 modules (287 inline 8-bit counters): 287 [0x7accc0, 0x7acddf),
INFO: Loaded 1 PC tables (287 PCs): 287 [0x585798,0x586988),
INFO: 0 files found in corpus1/
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
==231085==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000000b1 at pc 0x00000055d8af bp 0x7ffedc022840 sp 0x7ffedc022838
READ of size 1 at 0x6020000000b1 thread T0
#0 0x55d8ae in rapidjson::GenericStringStream<rapidjson::UTF8 >::Peek() const /home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/./../../include/rapidjson/stream.h:115:30
#1 0x55d8ae in void rapidjson::SkipWhitespace<rapidjson::GenericStringStream<rapidjson::UTF8 > >(rapidjson::GenericStringStream<rapidjson::UTF8 >&) /home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/./../../include/rapidjson/reader.h:269
#2 0x55d8ae in void rapidjson::GenericReader<rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator>::SkipWhitespaceAndComments<0u, rapidjson::GenericStringStream<rapidjson::UTF8 > >(rapidjson::GenericStringStream<rapidjson::UTF8 >&) /home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/./../../include/rapidjson/reader.h:561
#3 0x55d8ae in rapidjson::ParseResult rapidjson::GenericReader<rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator>::Parse<0u, rapidjson::GenericStringStream<rapidjson::UTF8 >, MyHandler>(rapidjson::GenericStringStream<rapidjson::UTF8 >&, MyHandler&) /home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/./../../include/rapidjson/reader.h:493
#4 0x55d57e in rapidjson::ParseResult rapidjson::GenericReader<rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator>::Parse<rapidjson::GenericStringStream<rapidjson::UTF8 >, MyHandler>(rapidjson::GenericStringStream<rapidjson::UTF8 >&, MyHandler&) /home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/./../../include/rapidjson/reader.h:527:16
#5 0x55d57e in LLVMFuzzerTestOneInput /home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/fuzz_reader.cpp:40
#6 0x42d4c7 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:515
#7 0x43174a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) [clone .constprop.310] /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:440
#8 0x4327eb in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<std::string, fuzzer::fuzzer_allocatorstd::string > const&) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:706
#9 0x432d72 in fuzzer::Fuzzer::Loop(std::vector<std::string, fuzzer::fuzzer_allocatorstd::string > const&) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:739
#10 0x427644 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:754
#11 0x41da42 in main /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20
#12 0x7f72189f2f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287
#13 0x41db03 in _start (/home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/fuzz-reader+0x41db03)

0x6020000000b1 is located 0 bytes to the right of 1-byte region [0x6020000000b0,0x6020000000b1)
allocated by thread T0 here:
#0 0x559258 in operator new[](unsigned long) /home/lx/5_4/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:95
#1 0x42d409 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:506
#2 0x43174a in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) [clone .constprop.310] /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:440
#3 0x4327eb in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<std::string, fuzzer::fuzzer_allocatorstd::string > const&) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:706
#4 0x432d72 in fuzzer::Fuzzer::Loop(std::vector<std::string, fuzzer::fuzzer_allocatorstd::string > const&) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:739
#5 0x427644 in fuzzer::FuzzerDriver(int*, char***, int ()(unsigned char const, unsigned long)) /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:754
#6 0x41da42 in main /home/lx/5_4/llvm/projects/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20
#7 0x7f72189f2f44 in __libc_start_main /build/eglibc-ripdx6/eglibc-2.19/csu/libc-start.c:287

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/lx/5_15/rapidjson/rapidjson-1.1.0/example/simplereader/./../../include/rapidjson/stream.h:115:30 in rapidjson::GenericStringStream<rapidjson::UTF8 >::Peek() const
Shadow bytes around the buggy address:
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff8000: fa fa 00 00 fa fa 00 fa fa fa 00 fa fa fa fd fa
=>0x0c047fff8010: fa fa 01 fa fa fa[01]fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==231085==ABORTING
MS: 0 ; base unit: 0000000000000000000000000000000000000000
0xa,
\x0a
artifact_prefix='./'; Test unit written to ./crash-adc83b19e793491b1c6ea0fd8b46cd9f32e592fc
Base64: Cg==

@StilesCrisis
Copy link
Contributor

Not a bug

This test is written improperly.
You are ignoring the Size parameter to the fuzzer function and reading off the end of the buffer. You must write a stream handler that stops at the end of the data buffer.
Also, you are not providing a corpus, so the fuzzer will have a hard time creating meaningful tests anyway.

@EnchantedJohn
Copy link
Author

Thank you for pointing to my fault@StilesCrisis. It is not a BUG.. I change my code in two ways. my code test Document.Parse()and reader.Parse().and I also add my corpus and seed corpus.then it looks like Parse() is stronger.Finally,I show my test code.

first code to test Document.parse()

#include "../../../include/rapidjson/document.h"
#include "../../../include/rapidjson/istreamwrapper.h"
#include <iostream>

using namespace rapidjson;
using namespace std;

class memstream : public std::istream {
  struct membuf : std::streambuf {
    membuf(const uint8_t *p, size_t l) {
      setg((char *)p, (char *)p, (char *)p + l); 
    }   
  };  
  membuf _buffer;

 public:
  memstream(const uint8_t *p, size_t l)
      : std::istream(&_buffer), _buffer(p, l) {
    rdbuf(&_buffer);
  }
};

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
    memstream json(Data, Size);
    IStreamWrapper isw(json);
    Document d;
    d.ParseStream(isw);
        return 0;
}

the secode code to test reader.Parse():


#include "../../../include/rapidjson/reader.h"
#include "../../../include/rapidjson/istreamwrapper.h"
#include <iostream>

using namespace rapidjson;
using namespace std;

struct MyHandler {
    bool Null() { cout << "Null()" << endl; return true; }
    bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
    bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
    bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
    bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
    bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
    bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
    bool RawNumber(const char* str, SizeType length, bool copy) {
        cout << "Number(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
        return true;
    }
    bool String(const char* str, SizeType length, bool copy) {
        cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
        return true;
    }
    bool StartObject() { cout << "StartObject()" << endl; return true; }
    bool Key(const char* str, SizeType length, bool copy) {
        cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
        return true;
    }
    bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
    bool StartArray() { cout << "StartArray()" << endl; return true; }
    bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
};

class memstream : public std::istream {
  struct membuf : std::streambuf {
    membuf(const uint8_t *p, size_t l) {
      setg((char *)p, (char *)p, (char *)p + l); 
    }   
  };  
  membuf _buffer;
  public:
  memstream(const uint8_t *p, size_t l)
      : std::istream(&_buffer), _buffer(p, l) {
    rdbuf(&_buffer);
  }
};

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{

    MyHandler handler;
    Reader reader;
    memstream json(Data, Size);
    IStreamWrapper isw(json);
    reader.Parse(isw, handler);
        return 0;
}

Thanks again.I just started to fuzzing test in a week ago.I have a lot to study.It is sorry for my mistake to borther your guys.

@StilesCrisis
Copy link
Contributor

No problem.
I've got a fuzzer hooked up to it already. You might have noticed some of the issues I've filed recently.

@EnchantedJohn
Copy link
Author

OK,I will finish this issue .Hope a good day for you. Thanks again!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants