Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: move fuzzing tests from google/oss-fuzz repository #4719

Merged
merged 1 commit into from
Oct 10, 2024
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
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 @@ -243,3 +243,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
Loading