Skip to content

Commit

Permalink
Merge pull request #1191 from tyler92/fuzzer_improvement
Browse files Browse the repository at this point in the history
Improve fuzzer
  • Loading branch information
kiplingw authored Apr 24, 2024
2 parents 2359c2d + 89cf458 commit 769c0c3
Show file tree
Hide file tree
Showing 21 changed files with 194 additions and 68 deletions.
6 changes: 6 additions & 0 deletions .reuse/dep5
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/

Files: tests/fuzzers/corpus/http-*.txt
Copyright: 2024 Mikhail Khachayants
License: Apache-2.0

8 changes: 8 additions & 0 deletions tests/fuzzers/corpus/http-1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
RGET / HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-10.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HSun, 06 Nov 1994 08:49:37 GMT
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-11.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HSunday, 06-Nov-94 08:49:37 GMT
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-12.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HFri Feb 11 16:30:00 2024
10 changes: 10 additions & 0 deletions tests/fuzzers/corpus/http-13.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
RPUT /upload.php?q=query_string&limit=10&offset=0 HTTP/1.1
Host: example.com
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Encoding: gzip, deflate, br;q=0.9, identity;q=0.5
Content-Length: 18
Content-Type: text/plain
Cookie: session_id=abc123; user_id=123456

This is the content
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-14.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cuser_id=123456; Max-Age=3600; Path=/account; Domain=example.com; Secure; HttpOnly; Expires=Sat, 11 Feb 2024 16:30:00 GMT
2 changes: 2 additions & 0 deletions tests/fuzzers/corpus/http-15.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Susers/:userid/A
users/meF
2 changes: 2 additions & 0 deletions tests/fuzzers/corpus/http-16.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Susers/?useridA
users/meF
2 changes: 2 additions & 0 deletions tests/fuzzers/corpus/http-17.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Susers/*/dataA
users/me/dataF
2 changes: 2 additions & 0 deletions tests/fuzzers/corpus/http-18.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Susers/:userid?/A
users/meF
6 changes: 6 additions & 0 deletions tests/fuzzers/corpus/http-2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
RPOST / HTTP/1.1
Host: www.example.re
Content-Type: application/x-www-form-urlencoded
Content-Length: 18

Job=100&Priority=2
10 changes: 10 additions & 0 deletions tests/fuzzers/corpus/http-3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
RPOST / HTTP/1.1
Host: www.example.re
Content-Type: text/plain
Transfer-Encoding: chunked

7
Mozilla
11
Developer Network
0
6 changes: 6 additions & 0 deletions tests/fuzzers/corpus/http-4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
RGET /index.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-5.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hgzip, deflate, br
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-6.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Happlication/x-www-form-urlencoded
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-7.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HContent-Length: 29
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-8.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hsession_id=abc123; user_id=123456
1 change: 1 addition & 0 deletions tests/fuzzers/corpus/http-9.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HBasic dXNlcjpwYXNzd29yZA==
197 changes: 130 additions & 67 deletions tests/fuzzers/fuzz_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,97 +5,160 @@
*/

#include <pistache/http.h>
#include <pistache/router.h>

using namespace Pistache;

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
template <class F>
void ignoreExceptions(const F& func)
{
std::string input(reinterpret_cast<const char*>(data), size);

// URI parsing
Http::Uri::Query query1;
query1.add(input, input);

// HTTP parsing
Pistache::Http::Header::CacheControl cc1;
try
{
cc1.parse(input);
func();
}
catch (...)
{ }

Pistache::Http::Header::Accept a1;
try
{
a1.parse(input);
}
catch (...)
{ }
}

Pistache::Http::Header::Accept a2;
try
{
a2.parse(input);
}
catch (...)
{ }
template <class T>
void parseHttpHeader(const std::string& input)
{
T header;
ignoreExceptions([&] { header.parse(input); });

Pistache::Http::Header::Authorization au;
try
{
au.parse(input);
}
catch (...)
{ }
std::stringstream oss;
header.write(oss);
}

Pistache::Http::Header::Expect e;
try
{
e.parse(input);
}
catch (...)
{ }
template <>
void parseHttpHeader<Pistache::Http::Header::Authorization>(const std::string& input)
{
Pistache::Http::Header::Authorization header;
ignoreExceptions([&] { header.parse(input); });
ignoreExceptions([&] { header.getMethod(); });
ignoreExceptions(
[&] {
const auto user = header.getBasicUser();
const auto password = header.getBasicPassword();
header.setBasicUserPassword(user, password);
});

Pistache::Http::Header::Connection connection;
try
{
connection.parse(input);
}
catch (...)
{ }
std::stringstream oss;
header.write(oss);
}

Pistache::Http::Header::Date d;
try
{
d.parse(input);
}
catch (...)
{ }
void fuzz_headers(const std::string& input)
{
parseHttpHeader<Pistache::Http::Header::Accept>(input);
parseHttpHeader<Pistache::Http::Header::CacheControl>(input);
parseHttpHeader<Pistache::Http::Header::Connection>(input);
parseHttpHeader<Pistache::Http::Header::AcceptEncoding>(input);
parseHttpHeader<Pistache::Http::Header::ContentEncoding>(input);
parseHttpHeader<Pistache::Http::Header::ContentLength>(input);
parseHttpHeader<Pistache::Http::Header::ContentType>(input);
parseHttpHeader<Pistache::Http::Header::Authorization>(input);
parseHttpHeader<Pistache::Http::Header::Date>(input);
parseHttpHeader<Pistache::Http::Header::Expect>(input);
parseHttpHeader<Pistache::Http::Header::Host>(input);
parseHttpHeader<Pistache::Http::Header::Server>(input);
}

Pistache::Http::Header::Host h;
try
void fuzz_cookies(const std::string& input)
{
Pistache::Http::CookieJar cookie_jar;
ignoreExceptions([&] { Pistache::Http::Cookie::fromString(input); });
ignoreExceptions([&] { cookie_jar.addFromRaw(input.data(), input.size()); });
}

void fuzz_request_parser(const std::string& input)
{
constexpr size_t maxDataSize = 4096;
Pistache::Http::RequestParser rparser(maxDataSize);

if (rparser.feed(input.data(), input.size()))
{
h.parse(input);
auto state = Pistache::Http::Private::State::Done;
ignoreExceptions([&] { state = rparser.parse(); });

if (state == Pistache::Http::Private::State::Again)
ignoreExceptions([&] { rparser.parse(); });
}
catch (...)
{ }
}

Pistache::Http::Header::ContentEncoding ce;
try
void fuzz_router(const std::string& input)
{
std::string path_input;
std::stringstream input_stream(input);
Pistache::Rest::SegmentTreeNode tree;

while (std::getline(input_stream, path_input, '\n'))
{
ce.parse(input);
if (path_input.size() < 2)
continue;

const int test_case = path_input.back();
path_input.pop_back();

const auto sanitized = Pistache::Rest::SegmentTreeNode::sanitizeResource(path_input);
std::shared_ptr<char> ptr(new char[sanitized.length()], std::default_delete<char[]>());
memcpy(ptr.get(), sanitized.data(), sanitized.length());
const std::string_view path { ptr.get(), sanitized.length() };

switch (test_case)
{
case 'A':
ignoreExceptions([&] {
Pistache::Rest::Route::Handler handler = [](auto...) { return Pistache::Rest::Route::Result::Ok; };
std::shared_ptr<char> ptr(new char[sanitized.length()], std::default_delete<char[]>());
memcpy(ptr.get(), sanitized.data(), sanitized.length());
const std::string_view path { ptr.get(), sanitized.length() };
tree.addRoute(path, handler, ptr);
});
break;
case 'R':
// ignoreExceptions([&] { tree.removeRoute(path); });
break;
case 'F':
ignoreExceptions([&] { tree.findRoute(path); });
break;
}
}
catch (...)
{ }
}

Pistache::Http::Header::ContentType ct;
try
void fuzz_other(const std::string& input)
{
// URI parsing
Http::Uri::Query query1;
query1.add(input, input);
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
if (size < 1)
return -1;

const uint8_t type = data[0];
const std::string input(reinterpret_cast<const char*>(data + 1), size - 1);

switch (type)
{
ct.parse(input);
case 'H':
fuzz_headers(input);
break;
case 'C':
fuzz_cookies(input);
break;
case 'R':
fuzz_request_parser(input);
break;
case 'S':
fuzz_router(input);
break;
case 'O':
fuzz_other(input);
break;
}
catch (...)
{ }

return 0;
}
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.9.20240419
0.2.9.20240421

0 comments on commit 769c0c3

Please sign in to comment.