test: fuzz test tr_torrent_metainfo.parseBenc() (#2891)

* test: fuzz test tr_urlParse()

* fix: stack error checking in benc parser

* test: fuzz test tr_torrent_metainfo.parseBenc()
This commit is contained in:
Charles Kerr 2022-04-06 15:26:13 -05:00 committed by GitHub
parent e88ebbc3e5
commit a134445caa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 39 deletions

View File

@ -6,7 +6,6 @@
#include <array>
#include <cctype> /* isdigit() */
#include <deque>
#include <cerrno>
#include <string_view>
#include <optional>
@ -144,26 +143,31 @@ struct MyHandler : public transmission::benc::Handler
bool Int64(int64_t value, Context const& /*context*/) final
{
if (tr_variant* variant = get_node(); variant != nullptr)
auto* const variant = get_node();
if (variant == nullptr)
{
tr_variantInitInt(variant, value);
return false;
}
tr_variantInitInt(variant, value);
return true;
}
bool String(std::string_view sv, Context const& /*context*/) final
{
if (tr_variant* variant = get_node(); variant != nullptr)
auto* const variant = get_node();
if (variant == nullptr)
{
if ((parse_opts_ & TR_VARIANT_PARSE_INPLACE) != 0)
{
tr_variantInitStrView(variant, sv);
}
else
{
tr_variantInitStr(variant, sv);
}
return false;
}
if ((parse_opts_ & TR_VARIANT_PARSE_INPLACE) != 0)
{
tr_variantInitStrView(variant, sv);
}
else
{
tr_variantInitStr(variant, sv);
}
return true;
@ -171,12 +175,14 @@ struct MyHandler : public transmission::benc::Handler
bool StartDict(Context const& /*context*/) final
{
if (tr_variant* variant = get_node(); variant != nullptr)
auto* const variant = get_node();
if (variant == nullptr)
{
tr_variantInitDict(variant, 0);
stack_.push_back(variant);
return false;
}
tr_variantInitDict(variant, 0);
stack_.push_back(variant);
return true;
}
@ -189,26 +195,36 @@ struct MyHandler : public transmission::benc::Handler
bool EndDict(Context const& /*context*/) final
{
stack_.pop_back();
if (std::empty(stack_))
{
return false;
}
stack_.pop_back();
return true;
}
bool StartArray(Context const& /*context*/) final
{
if (tr_variant* variant = get_node(); variant != nullptr)
auto* const variant = get_node();
if (variant == nullptr)
{
tr_variantInitList(variant, 0);
stack_.push_back(variant);
return false;
}
tr_variantInitList(variant, 0);
stack_.push_back(variant);
return true;
}
bool EndArray(Context const& /*context*/) final
{
stack_.pop_back();
if (std::empty(stack_))
{
return false;
}
stack_.pop_back();
return true;
}
@ -221,19 +237,14 @@ private:
{
node = top_;
}
else
else if (auto* parent = stack_.back(); tr_variantIsList(parent))
{
auto* parent = stack_.back();
if (tr_variantIsList(parent))
{
node = tr_variantListAdd(parent);
}
else if (key_ && tr_variantIsDict(parent))
{
node = tr_variantDictAdd(parent, *key_);
key_.reset();
}
node = tr_variantListAdd(parent);
}
else if (key_ && tr_variantIsDict(parent))
{
node = tr_variantDictAdd(parent, *key_);
key_.reset();
}
return node;
@ -245,12 +256,7 @@ bool tr_variantParseBenc(tr_variant& top, int parse_opts, std::string_view benc,
using Stack = transmission::benc::ParserStack<512>;
auto stack = Stack{};
auto handler = MyHandler{ &top, parse_opts };
bool const ok = transmission::benc::parse(benc, stack, handler, setme_end, error);
if (!ok)
{
tr_variantFree(&top);
}
return ok;
return transmission::benc::parse(benc, stack, handler, setme_end, error);
}
/****

View File

@ -4,12 +4,12 @@
// License text can be found in the licenses/ folder.
#include <array>
#include <cerrno>
#include <cstring>
#include <string_view>
#include "transmission.h"
#include "crypto-utils.h"
#include "error.h"
#include "torrent-metainfo.h"
#include "torrent.h"
@ -85,6 +85,34 @@ TEST_F(TorrentMetainfoTest, bucket)
}
}
TEST_F(TorrentMetainfoTest, parseBencFuzzRegressions)
{
static auto constexpr Tests = std::array<std::string_view, 1>{
"ZC/veNSVW0Ss+KGfMqH4DQqtYXzgmVi5oBi0XlxviLytlwwjf7MLanOcnS73eSB/iye83hVyvSWg27tPl5oqWdNEZ0euMbo7E8FH/xgTvUEOnBVgvPno50CyI7c5F2QTw16avUB7dvGzx5xIjzJ2qkD2BsNtOoiZI3skC6XwSifsDfJUN8NxHFiwvWxmZRLq2eQlE2wGxAW5aLj6U1MHDzPZ83+2o81pRyMr11bHmWFcNorTGLeOpHBd9veduHpNOKNwOatoXeb57jZCy1Zmu9y/wCuUx6DP3I5FGQ/t3AYh7w028Z/zgIlvWat6QjqSPp7j1nEbl6SNZNl1doGmusl9hvRsbaCq9b1XHpTDtQSJ8Owj07fph0p0ZVu5kJpQBfOGsHLh6ALVrTepptIvcnNW9+nauE+NJa2z+9Yla7780sCdBsGYZZA6HUr0J9GXES7+uRPPBwAl2YB1qWhCsOCClixTiAlwrsBl1bJ/a4FV04aU5jXDEYrpJMzdSAEoypDWMsn3Fc5umLqJ1jtqPqykKY0HjPrCkVAMmvmacauBzIj5Eg/uw0xtZp+wXdLQv8qyuXgsJs7dExZbgTgfPY4niTBpftM6YFQrCx/IxiMshYp7tMolykoed/8gZMm6yyWizzml4BlvnvY3+J2eVKRvS7QToRKxN5eFP9l/pflrK+8cHbwVnjQ1pE3hTQACmNIQHRTY2QoOGwG+HTwo48akfbJnjJ3F0iN6miy7lvv5u0p1rpbM2On5FJ3G98OYnzGIxf8BomHvVp/3eX6QJZUMZKsUTpgbRqg0AJH9FjiERQ9v6B25Va+Q0yV8z5DmiA5AgyIwkIzlSBAl0PYsNaw+rH06a93yBhAfK6EPSArYLjMI6o/1kF4UxNyfE+F79xbdCAKRAX3iJ7DH1GncFoIQ1fZd/uZaF9tXjViQ7P/sHuKdZvfLpvJq88JV5Pcdsfdlle86QAF4weB+k/k8f/xgvxRNbbcAfjLvEHhDBzfEvHkgFrW19WvLHyAqjjUovpecIu3KeCqwyOr1dHViUVelxqc5BklyGQ+Asd6GnWPSzO5Hamj4rYrapgogEup5PKm1j2CgL2HH2tySWwjgtOWbooGhsdBnCeQOsapCxwc6ALtudG4Q9RBu6A6pLUfFE3rm1RuvNGoJNHiEQ4BAFiqLpYJd4lR7V2fI6EIKug0dB3SpHpUeNCQbG67IM+kVe0I+vP3cECGOGXo="sv,
};
for (auto const& test : Tests)
{
auto tm = tr_torrent_metainfo{};
tm.parseBenc(tr_base64_decode(test));
}
}
TEST_F(TorrentMetainfoTest, parseBencFuzz)
{
auto buf = std::vector<char>{};
for (size_t i = 0; i < 100000; ++i)
{
buf.resize(tr_rand_int(1024));
tr_rand_buffer(std::data(buf), std::size(buf));
// std::cerr << '[' << tr_base64_encode({ std::data(buf), std::size(buf) }) << ']' << std::endl;
auto tm = tr_torrent_metainfo{};
tm.parseBenc({ std::data(buf), std::size(buf) });
}
}
#if 0
TEST_F(TorrentMetainfoTest, sanitize)
{

View File

@ -12,6 +12,8 @@
#endif
#include "transmission.h"
#include "crypto-utils.h"
#include "platform.h"
#include "web-utils.h"
@ -128,6 +130,18 @@ TEST_F(WebUtilsTest, urlParse)
EXPECT_EQ(8080, parsed->port);
}
TEST(WebUtilsTest, urlParseFuzz)
{
auto buf = std::vector<char>{};
for (size_t i = 0; i < 100000; ++i)
{
buf.resize(tr_rand_int(1024));
tr_rand_buffer(std::data(buf), std::size(buf));
tr_urlParse({ std::data(buf), std::size(buf) });
}
}
TEST_F(WebUtilsTest, urlNextQueryPair)
{
auto constexpr Query = "a=1&b=two&c=si&d_has_no_val&e=&f&g=gee"sv;