Skip to content

Commit

Permalink
Add cpp-httplib to oss-fuzz (yhirose#684)
Browse files Browse the repository at this point in the history
* *Add server fuzzer target  and seed corpus
* Add fuzz_test option to Makefile

* Fix yhirose#685

* Try to fix Github actions on Ubuntu

* Added ReadTimeoutSSL test

* Comment out `-fsanitize=address`

* Rebase upstream changes

* remove address sanitizer temporarily

* Add separate Makefile for fuzzing

* 1. Remove special char from dictionary
2. Clean fuzzing/Makefile

* Use specific path to avoid accidently linking openssl version brought in by oss-fuzz

* remove addition of flags

* Refactor Makefile

* Add missing newline

* Add fuzztest to github workflow

* Fix

Co-authored-by: yhirose <[email protected]>
  • Loading branch information
omjego and yhirose authored Oct 15, 2020
1 parent cc5147a commit 5292142
Show file tree
Hide file tree
Showing 9 changed files with 418 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ jobs:
- name: make
if: matrix.os != 'windows-latest'
run: cd test && make
- name: check fuzz test target
if: matrix.os == 'ubuntu-latest'
run: cd test && make -f Makefile.fuzz_test
- name: setup msbuild on windows
if: matrix.os == 'windows-latest'
uses: warrenbuckley/Setup-MSBuild@v1
Expand Down
1 change: 0 additions & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

#CXX = clang++
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion #-fsanitize=address

Expand Down
36 changes: 36 additions & 0 deletions test/Makefile.fuzz_test
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

#CXX = clang++
CXXFLAGS += -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion

OPENSSL_DIR = /usr/local/opt/[email protected]
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto

ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz

BROTLI_DIR = /usr/local/opt/brotli
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec

# By default, use standalone_fuzz_target_runner.
# This runner does no fuzzing, but simply executes the inputs
# provided via parameters.
# Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a"
# to link the fuzzer(s) against a real fuzzing engine.
# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o

# Runs server_fuzzer.cc based on value of $(LIB_FUZZING_ENGINE).
# Usage: make fuzz_test LIB_FUZZING_ENGINE=/path/to/libFuzzer
all fuzz_test: server_fuzzer
./server_fuzzer fuzzing/corpus/*

# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
server_fuzzer : fuzzing/server_fuzzer.cc ../httplib.h standalone_fuzz_target_runner.o
$(CXX) $(CXXFLAGS) -o $@ $< $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread

# Standalone fuzz runner, which just reads inputs from fuzzing/corpus/ dir and
# feeds it to server_fuzzer.
standalone_fuzz_target_runner.o : fuzzing/standalone_fuzz_target_runner.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<

clean:
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
26 changes: 26 additions & 0 deletions test/fuzzing/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

#CXX = clang++
# Do not add default sanitizer flags here as OSS-fuzz adds its own sanitizer flags.
CXXFLAGS += -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I../.. -I. -Wall -Wextra -Wtype-limits -Wconversion

OPENSSL_DIR = /usr/local/opt/[email protected]

# Using full path to libssl and libcrypto to avoid accidentally picking openssl libs brought in by msan.
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -I$(OPENSSL_DIR)/lib /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a

ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz

BROTLI_DIR = /usr/local/opt/brotli
# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec

# Runs all the tests and also fuzz tests against seed corpus.
all : server_fuzzer
./server_fuzzer corpus/*

# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
server_fuzzer : server_fuzzer.cc ../../httplib.h
$(CXX) $(CXXFLAGS) -o $@ $< -Wl,-Bstatic $(OPENSSL_SUPPORT) -Wl,-Bdynamic -ldl $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
zip -q -r server_fuzzer_seed_corpus.zip corpus

clean:
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip
1 change: 1 addition & 0 deletions test/fuzzing/corpus/1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PUT /search/sample?a=12 HTTP/1.1
5 changes: 5 additions & 0 deletions test/fuzzing/corpus/2
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GET /hello.htm HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
88 changes: 88 additions & 0 deletions test/fuzzing/server_fuzzer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <memory>
#include <httplib.h>

class FuzzedStream : public httplib::Stream {
public:
FuzzedStream(const uint8_t* data, size_t size)
: data_(data), size_(size), read_pos_(0) {}

ssize_t read(char* ptr, size_t size) override {
if (size + read_pos_ > size_) {
size = size_ - read_pos_;
}
memcpy(ptr, data_ + read_pos_, size);
read_pos_ += size;
return size;
}

ssize_t write(const char* ptr, size_t size) override {
response_.append(ptr, size);
return static_cast<int>(size);
}

int write(const char* ptr) { return write(ptr, strlen(ptr)); }

int write(const std::string& s) { return write(s.data(), s.size()); }

std::string get_remote_addr() const { return ""; }

bool is_readable() const override { return true; }

bool is_writable() const override { return true; }

void get_remote_ip_and_port(std::string &ip, int &port) const override {
ip = "127.0.0.1";
port = 8080;
}

private:
const uint8_t* data_;
size_t size_;
size_t read_pos_;
std::string response_;
};

class FuzzableServer : public httplib::Server {
public:
void ProcessFuzzedRequest(FuzzedStream& stream) {
bool connection_close = false;
process_request(stream, /*last_connection=*/false, connection_close,
nullptr);
}
};

static FuzzableServer g_server;

extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
g_server.Get(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Post(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Put(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Patch(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Delete(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
g_server.Options(R"(.*)",
[&](const httplib::Request& req, httplib::Response& res) {
res.set_content("response content", "text/plain");
});
return 0;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedStream stream{data, size};
g_server.ProcessFuzzedRequest(stream);
return 0;
}
Loading

0 comments on commit 5292142

Please sign in to comment.