Skip to content

Commit

Permalink
test: move fuzzing tests from google/oss-fuzz repository (#4719)
Browse files Browse the repository at this point in the history
  • Loading branch information
tyler92 authored Oct 10, 2024
1 parent c038b52 commit aa0faed
Show file tree
Hide file tree
Showing 40 changed files with 857 additions and 0 deletions.
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ option(ENABLE_COMPILER_WARNINGS
option(ENABLE_SAMPLES
"Set to OFF|ON (default is OFF) to control build of POCO samples" OFF)

option(ENABLE_FUZZING
"Set to OFF|ON (default is OFF) to control build of fuzzing targets for oss-fuzz (Clang compiler is required)" OFF)

option(POCO_UNBUNDLED
"Set to OFF|ON (default is OFF) to control linking dependencies as external" OFF)

Expand All @@ -226,6 +229,14 @@ else()
message(STATUS "Building without tests & samples")
endif()

if(ENABLE_FUZZING)
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
message(FATAL_ERROR "ENABLE_FUZZING flag requires using Clang compiler")
else()
message(STATUS "Building fuzzing test targets with engine $ENV{LIB_FUZZING_ENGINE}")
endif()
endif()

if(POCO_UNBUNDLED)
message(STATUS "Using external sqlite, zlib, pcre2, expat, libpng, ...")
else()
Expand Down
4 changes: 4 additions & 0 deletions Foundation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,7 @@ if(ENABLE_TESTS)
endif()
add_subdirectory(testsuite)
endif()

if(ENABLE_FUZZING)
add_subdirectory(fuzzing)
endif()
7 changes: 7 additions & 0 deletions Foundation/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
add_executable(Foundation-datetime-fuzzer DateTimeParse.cpp)
target_link_libraries(Foundation-datetime-fuzzer PUBLIC Poco::Foundation)
set_target_properties(Foundation-datetime-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})

add_executable(Foundation-misc-fuzzer MiscFuzzing.cpp)
target_link_libraries(Foundation-misc-fuzzer PUBLIC Poco::Foundation)
set_target_properties(Foundation-misc-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})
46 changes: 46 additions & 0 deletions Foundation/fuzzing/DateTimeParse.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "Poco/DateTimeParser.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeFormatter.h"

using namespace Poco;

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
const std::string input(reinterpret_cast<const char*>(data), size);

const std::string formats[] = {
DateTimeFormat::ISO8601_FORMAT,
DateTimeFormat::ISO8601_FRAC_FORMAT,
DateTimeFormat::RFC822_FORMAT,
DateTimeFormat::RFC1123_FORMAT,
DateTimeFormat::HTTP_FORMAT,
DateTimeFormat::RFC850_FORMAT,
DateTimeFormat::RFC1036_FORMAT,
DateTimeFormat::ASCTIME_FORMAT,
DateTimeFormat::SORTABLE_FORMAT,
"%m/%d/%y %h:%M %a",
"T%H:%M:%F",
};

int tzd = 0;
DateTime dt;

for (const auto& format : formats)
{
DateTimeParser::tryParse(format, input, dt, tzd);
DateTimeFormatter::format(dt.timestamp(), format, tzd);
}

dt.makeLocal(tzd);
dt.makeUTC(tzd);

try
{
dt = DateTimeParser::parse(input, tzd);
}
catch (const std::exception&)
{
}

return 0;
}
95 changes: 95 additions & 0 deletions Foundation/fuzzing/MiscFuzzing.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "Poco/URI.h"
#include "Poco/Path.h"
#include "Poco/UUID.h"
#include "Poco/UTF8String.h"
#include <fuzzer/FuzzedDataProvider.h>

using namespace Poco;

static void fuzzURI(FuzzedDataProvider& dataProvider)
{
try
{
URI uri1(dataProvider.ConsumeRandomLengthString());
URI uri2(uri1, dataProvider.ConsumeRandomLengthString());

URI uri3(uri2);
uri3.normalize();
uri3.setQueryParameters(uri1.getQueryParameters());
uri2 = uri3.toString();
}
catch (const std::exception&)
{
}
}

static void fuzzPath(FuzzedDataProvider& dataProvider)
{
try
{
Path path1;
path1.tryParse(dataProvider.ConsumeRandomLengthString());

Path path2(path1, Path(dataProvider.ConsumeRandomLengthString()));
Path path3 = path1.absolute();
Path path4 = Path::expand(dataProvider.ConsumeRandomLengthString());

const auto style1 = dataProvider.ConsumeIntegralInRange<char>(Path::PATH_UNIX, Path::PATH_GUESS);
const auto style2 = dataProvider.ConsumeIntegralInRange<char>(Path::PATH_UNIX, Path::PATH_GUESS);
path3.assign(path4.toString(static_cast<Path::Style>(style1)), static_cast<Path::Style>(style2));
}
catch (const std::exception&)
{
}
}

static void fuzzUUID(FuzzedDataProvider& dataProvider)
{
try
{
UUID uuid1(dataProvider.ConsumeRandomLengthString());
UUID uuid2(uuid1.toString());
uuid2.tryParse(dataProvider.ConsumeRandomLengthString());
}
catch (const std::exception&)
{
}
}

static void fuzzUTF8String(FuzzedDataProvider& dataProvider)
{
try
{
auto str1 = UTF8::unescape(dataProvider.ConsumeRandomLengthString());
auto str2 = UTF8::escape(str1);

UTF8::toUpperInPlace(str1);
UTF8::toLowerInPlace(str2);
}
catch (const std::exception&)
{
}
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
FuzzedDataProvider dataProvider(data, size);

switch (dataProvider.ConsumeIntegral<char>())
{
case 0:
fuzzURI(dataProvider);
break;
case 1:
fuzzPath(dataProvider);
break;
case 2:
fuzzUUID(dataProvider);
break;
case 3:
fuzzUTF8String(dataProvider);
break;
}

return 0;
}
4 changes: 4 additions & 0 deletions JSON/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,7 @@ endif()
if(ENABLE_TESTS)
add_subdirectory(testsuite)
endif()

if(ENABLE_FUZZING)
add_subdirectory(fuzzing)
endif()
3 changes: 3 additions & 0 deletions JSON/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_executable(JSON-parse-fuzzer JsonParse.cpp)
target_link_libraries(JSON-parse-fuzzer PUBLIC Poco::JSON)
set_target_properties(JSON-parse-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})
26 changes: 26 additions & 0 deletions JSON/fuzzing/JsonParse.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "Poco/JSON/Parser.h"

using namespace Poco;
using namespace Poco::JSON;

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
std::string json(reinterpret_cast<const char*>(data), size);
Parser parser;
Dynamic::Var result;

try
{
result = parser.parse(json);
}
catch (Exception& e)
{
return 0;
}
catch (const std::exception& e)
{
return 0;
}

return 0;
}
4 changes: 4 additions & 0 deletions JWT/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ POCO_GENERATE_PACKAGE(JWT)
if(ENABLE_TESTS)
add_subdirectory(testsuite)
endif()

if(ENABLE_FUZZING)
add_subdirectory(fuzzing)
endif()
3 changes: 3 additions & 0 deletions JWT/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
add_executable(JWT-decode-fuzzer JWTDecode.cpp)
target_link_libraries(JWT-decode-fuzzer PUBLIC Poco::JWT)
set_target_properties(JWT-decode-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})
47 changes: 47 additions & 0 deletions JWT/fuzzing/JWTDecode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "Poco/JWT/Token.h"
#include "Poco/JWT/Signer.h"

using namespace Poco;
using namespace Poco::JWT;

extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
{
Crypto::initializeCrypto();
return 0;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
const std::string input(reinterpret_cast<const char*>(data), size);

Signer signer;
signer.addAllAlgorithms();
signer.setHMACKey("secret");

try
{
// verify untrusted input
Token token;
token = signer.verify(input);
}
catch (const Exception&)
{
}

for (const auto& algorithm : signer.getAlgorithms())
{
try
{
// sign and verify again
Token token(input);
token.setAudience(token.getAudience());
signer.sign(token, algorithm);
token = signer.verify(token.toString());
}
catch (const Exception&)
{
}
}

return 0;
}
3 changes: 3 additions & 0 deletions Net/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,6 @@ if(ENABLE_TESTS)
add_subdirectory(testsuite)
endif()

if(ENABLE_FUZZING)
add_subdirectory(fuzzing)
endif()
8 changes: 8 additions & 0 deletions Net/fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
add_executable(Net-mail-parser-fuzzer MailParse.cpp)
target_link_libraries(Net-mail-parser-fuzzer PUBLIC Poco::Net)
set_target_properties(Net-mail-parser-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})

add_executable(Net-http-parser-fuzzer HTTPParse.cpp)
target_link_libraries(Net-http-parser-fuzzer PUBLIC Poco::Net)
set_target_properties(Net-http-parser-fuzzer PROPERTIES LINK_FLAGS $ENV{LIB_FUZZING_ENGINE})

96 changes: 96 additions & 0 deletions Net/fuzzing/HTTPParse.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include "Poco/MemoryStream.h"
#include "Poco/Net/EscapeHTMLStream.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/Net/HTTPCredentials.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/OAuth10Credentials.h"
#include "Poco/Net/OAuth20Credentials.h"
#include "Poco/Net/DNS.h"
#include "Poco/NullStream.h"

using namespace Poco;
using namespace Poco::Net;

template <class F>
void catchExceptions(const F& func)
{
try
{
func();
}
catch (const std::exception&)
{
}
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
NullOutputStream null;

// HTTPRequest parsing
catchExceptions(
[&]
{
MemoryInputStream stream(reinterpret_cast<const char*>(data), size);
HTTPRequest request;
request.read(stream);
request.write(null);

HTTPCredentials creds;
creds.fromURI(URI(request.getURI()));
creds.updateAuthInfo(request);
creds.updateProxyAuthInfo(request);
});

// HTTPResponse parsing
catchExceptions(
[&]
{
MemoryInputStream stream(reinterpret_cast<const char*>(data), size);
HTTPResponse response;
response.read(stream);
response.write(null);

HTTPRequest request(HTTPRequest::HTTP_GET, "/");
request.setHost(DNS::encodeIDN(DNS::decodeIDN(response.get(HTTPRequest::HOST))));

HTTPCredentials creds;
creds.authenticate(request, response);
creds.proxyAuthenticate(request, response);
});

// OAuth10Credentials
catchExceptions(
[&]
{
MemoryInputStream stream(reinterpret_cast<const char*>(data), size);
HTTPRequest request;
request.read(stream);

EscapeHTMLOutputStream htmlStream(null);
HTMLForm form(request, stream);
form.prepareSubmit(request);
form.write(htmlStream);

OAuth10Credentials oauth10(request);
oauth10.verify(request, URI(request.getURI()), form);
oauth10.authenticate(request, URI(request.getURI()), form,
request.hasToken("X-Method", "Plain") ? OAuth10Credentials::SIGN_PLAINTEXT
: OAuth10Credentials::SIGN_HMAC_SHA1);
});

// OAuth20Credentials
catchExceptions(
[&]
{
MemoryInputStream stream(reinterpret_cast<const char*>(data), size);
HTTPRequest request;
request.read(stream);

OAuth20Credentials oauth20(request);
oauth20.authenticate(request);
});

return 0;
}
Loading

0 comments on commit aa0faed

Please sign in to comment.