Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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/openssl@1.1
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/openssl@1.1

# 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