Skip to content

Commit 5292142

Browse files
omjegoyhirose
andauthored
Add cpp-httplib to oss-fuzz (#684)
* *Add server fuzzer target and seed corpus * Add fuzz_test option to Makefile * Fix #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]>
1 parent cc5147a commit 5292142

File tree

9 files changed

+418
-1
lines changed

9 files changed

+418
-1
lines changed

.github/workflows/test.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
- name: make
2828
if: matrix.os != 'windows-latest'
2929
run: cd test && make
30+
- name: check fuzz test target
31+
if: matrix.os == 'ubuntu-latest'
32+
run: cd test && make -f Makefile.fuzz_test
3033
- name: setup msbuild on windows
3134
if: matrix.os == 'windows-latest'
3235
uses: warrenbuckley/Setup-MSBuild@v1

test/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
#CXX = clang++
32
CXXFLAGS = -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion #-fsanitize=address
43

test/Makefile.fuzz_test

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
#CXX = clang++
3+
CXXFLAGS += -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I.. -I. -Wall -Wextra -Wtype-limits -Wconversion
4+
5+
OPENSSL_DIR = /usr/local/opt/[email protected]
6+
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -L$(OPENSSL_DIR)/lib -lssl -lcrypto
7+
8+
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
9+
10+
BROTLI_DIR = /usr/local/opt/brotli
11+
BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
12+
13+
# By default, use standalone_fuzz_target_runner.
14+
# This runner does no fuzzing, but simply executes the inputs
15+
# provided via parameters.
16+
# Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a"
17+
# to link the fuzzer(s) against a real fuzzing engine.
18+
# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
19+
LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
20+
21+
# Runs server_fuzzer.cc based on value of $(LIB_FUZZING_ENGINE).
22+
# Usage: make fuzz_test LIB_FUZZING_ENGINE=/path/to/libFuzzer
23+
all fuzz_test: server_fuzzer
24+
./server_fuzzer fuzzing/corpus/*
25+
26+
# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
27+
server_fuzzer : fuzzing/server_fuzzer.cc ../httplib.h standalone_fuzz_target_runner.o
28+
$(CXX) $(CXXFLAGS) -o $@ $< $(OPENSSL_SUPPORT) $(ZLIB_SUPPORT) $(BROTLI_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
29+
30+
# Standalone fuzz runner, which just reads inputs from fuzzing/corpus/ dir and
31+
# feeds it to server_fuzzer.
32+
standalone_fuzz_target_runner.o : fuzzing/standalone_fuzz_target_runner.cpp
33+
$(CXX) $(CXXFLAGS) -c -o $@ $<
34+
35+
clean:
36+
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip

test/fuzzing/Makefile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
#CXX = clang++
3+
# Do not add default sanitizer flags here as OSS-fuzz adds its own sanitizer flags.
4+
CXXFLAGS += -ggdb -O0 -std=c++11 -DGTEST_USE_OWN_TR1_TUPLE -I../.. -I. -Wall -Wextra -Wtype-limits -Wconversion
5+
6+
OPENSSL_DIR = /usr/local/opt/[email protected]
7+
8+
# Using full path to libssl and libcrypto to avoid accidentally picking openssl libs brought in by msan.
9+
OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -I$(OPENSSL_DIR)/include -I$(OPENSSL_DIR)/lib /usr/local/lib/libssl.a /usr/local/lib/libcrypto.a
10+
11+
ZLIB_SUPPORT = -DCPPHTTPLIB_ZLIB_SUPPORT -lz
12+
13+
BROTLI_DIR = /usr/local/opt/brotli
14+
# BROTLI_SUPPORT = -DCPPHTTPLIB_BROTLI_SUPPORT -I$(BROTLI_DIR)/include -L$(BROTLI_DIR)/lib -lbrotlicommon -lbrotlienc -lbrotlidec
15+
16+
# Runs all the tests and also fuzz tests against seed corpus.
17+
all : server_fuzzer
18+
./server_fuzzer corpus/*
19+
20+
# Fuzz target, so that you can choose which $(LIB_FUZZING_ENGINE) to use.
21+
server_fuzzer : server_fuzzer.cc ../../httplib.h
22+
$(CXX) $(CXXFLAGS) -o $@ $< -Wl,-Bstatic $(OPENSSL_SUPPORT) -Wl,-Bdynamic -ldl $(ZLIB_SUPPORT) $(LIB_FUZZING_ENGINE) -pthread
23+
zip -q -r server_fuzzer_seed_corpus.zip corpus
24+
25+
clean:
26+
rm -f server_fuzzer pem *.0 *.o *.1 *.srl *.zip

test/fuzzing/corpus/1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PUT /search/sample?a=12 HTTP/1.1

test/fuzzing/corpus/2

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GET /hello.htm HTTP/1.1
2+
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
3+
Accept-Language: en-us
4+
Accept-Encoding: gzip, deflate
5+
Connection: Keep-Alive

test/fuzzing/server_fuzzer.cc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include <memory>
2+
#include <httplib.h>
3+
4+
class FuzzedStream : public httplib::Stream {
5+
public:
6+
FuzzedStream(const uint8_t* data, size_t size)
7+
: data_(data), size_(size), read_pos_(0) {}
8+
9+
ssize_t read(char* ptr, size_t size) override {
10+
if (size + read_pos_ > size_) {
11+
size = size_ - read_pos_;
12+
}
13+
memcpy(ptr, data_ + read_pos_, size);
14+
read_pos_ += size;
15+
return size;
16+
}
17+
18+
ssize_t write(const char* ptr, size_t size) override {
19+
response_.append(ptr, size);
20+
return static_cast<int>(size);
21+
}
22+
23+
int write(const char* ptr) { return write(ptr, strlen(ptr)); }
24+
25+
int write(const std::string& s) { return write(s.data(), s.size()); }
26+
27+
std::string get_remote_addr() const { return ""; }
28+
29+
bool is_readable() const override { return true; }
30+
31+
bool is_writable() const override { return true; }
32+
33+
void get_remote_ip_and_port(std::string &ip, int &port) const override {
34+
ip = "127.0.0.1";
35+
port = 8080;
36+
}
37+
38+
private:
39+
const uint8_t* data_;
40+
size_t size_;
41+
size_t read_pos_;
42+
std::string response_;
43+
};
44+
45+
class FuzzableServer : public httplib::Server {
46+
public:
47+
void ProcessFuzzedRequest(FuzzedStream& stream) {
48+
bool connection_close = false;
49+
process_request(stream, /*last_connection=*/false, connection_close,
50+
nullptr);
51+
}
52+
};
53+
54+
static FuzzableServer g_server;
55+
56+
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
57+
g_server.Get(R"(.*)",
58+
[&](const httplib::Request& req, httplib::Response& res) {
59+
res.set_content("response content", "text/plain");
60+
});
61+
g_server.Post(R"(.*)",
62+
[&](const httplib::Request& req, httplib::Response& res) {
63+
res.set_content("response content", "text/plain");
64+
});
65+
g_server.Put(R"(.*)",
66+
[&](const httplib::Request& req, httplib::Response& res) {
67+
res.set_content("response content", "text/plain");
68+
});
69+
g_server.Patch(R"(.*)",
70+
[&](const httplib::Request& req, httplib::Response& res) {
71+
res.set_content("response content", "text/plain");
72+
});
73+
g_server.Delete(R"(.*)",
74+
[&](const httplib::Request& req, httplib::Response& res) {
75+
res.set_content("response content", "text/plain");
76+
});
77+
g_server.Options(R"(.*)",
78+
[&](const httplib::Request& req, httplib::Response& res) {
79+
res.set_content("response content", "text/plain");
80+
});
81+
return 0;
82+
}
83+
84+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
85+
FuzzedStream stream{data, size};
86+
g_server.ProcessFuzzedRequest(stream);
87+
return 0;
88+
}

0 commit comments

Comments
 (0)