mirror of
https://github.com/transmission/transmission
synced 2025-03-10 14:13:23 +00:00
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:
parent
e88ebbc3e5
commit
a134445caa
3 changed files with 87 additions and 39 deletions
|
@ -6,7 +6,6 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cctype> /* isdigit() */
|
#include <cctype> /* isdigit() */
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <cerrno>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
@ -144,26 +143,31 @@ struct MyHandler : public transmission::benc::Handler
|
||||||
|
|
||||||
bool Int64(int64_t value, Context const& /*context*/) final
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String(std::string_view sv, Context const& /*context*/) final
|
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)
|
return false;
|
||||||
{
|
}
|
||||||
tr_variantInitStrView(variant, sv);
|
|
||||||
}
|
if ((parse_opts_ & TR_VARIANT_PARSE_INPLACE) != 0)
|
||||||
else
|
{
|
||||||
{
|
tr_variantInitStrView(variant, sv);
|
||||||
tr_variantInitStr(variant, sv);
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
tr_variantInitStr(variant, sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -171,12 +175,14 @@ struct MyHandler : public transmission::benc::Handler
|
||||||
|
|
||||||
bool StartDict(Context const& /*context*/) final
|
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);
|
return false;
|
||||||
stack_.push_back(variant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr_variantInitDict(variant, 0);
|
||||||
|
stack_.push_back(variant);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,26 +195,36 @@ struct MyHandler : public transmission::benc::Handler
|
||||||
|
|
||||||
bool EndDict(Context const& /*context*/) final
|
bool EndDict(Context const& /*context*/) final
|
||||||
{
|
{
|
||||||
stack_.pop_back();
|
if (std::empty(stack_))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_.pop_back();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StartArray(Context const& /*context*/) final
|
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);
|
return false;
|
||||||
stack_.push_back(variant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr_variantInitList(variant, 0);
|
||||||
|
stack_.push_back(variant);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EndArray(Context const& /*context*/) final
|
bool EndArray(Context const& /*context*/) final
|
||||||
{
|
{
|
||||||
stack_.pop_back();
|
if (std::empty(stack_))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_.pop_back();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,19 +237,14 @@ private:
|
||||||
{
|
{
|
||||||
node = top_;
|
node = top_;
|
||||||
}
|
}
|
||||||
else
|
else if (auto* parent = stack_.back(); tr_variantIsList(parent))
|
||||||
{
|
{
|
||||||
auto* parent = stack_.back();
|
node = tr_variantListAdd(parent);
|
||||||
|
}
|
||||||
if (tr_variantIsList(parent))
|
else if (key_ && tr_variantIsDict(parent))
|
||||||
{
|
{
|
||||||
node = tr_variantListAdd(parent);
|
node = tr_variantDictAdd(parent, *key_);
|
||||||
}
|
key_.reset();
|
||||||
else if (key_ && tr_variantIsDict(parent))
|
|
||||||
{
|
|
||||||
node = tr_variantDictAdd(parent, *key_);
|
|
||||||
key_.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
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>;
|
using Stack = transmission::benc::ParserStack<512>;
|
||||||
auto stack = Stack{};
|
auto stack = Stack{};
|
||||||
auto handler = MyHandler{ &top, parse_opts };
|
auto handler = MyHandler{ &top, parse_opts };
|
||||||
bool const ok = transmission::benc::parse(benc, stack, handler, setme_end, error);
|
return transmission::benc::parse(benc, stack, handler, setme_end, error);
|
||||||
if (!ok)
|
|
||||||
{
|
|
||||||
tr_variantFree(&top);
|
|
||||||
}
|
|
||||||
return ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
// License text can be found in the licenses/ folder.
|
// License text can be found in the licenses/ folder.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cerrno>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "transmission.h"
|
#include "transmission.h"
|
||||||
|
|
||||||
|
#include "crypto-utils.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "torrent-metainfo.h"
|
#include "torrent-metainfo.h"
|
||||||
#include "torrent.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
|
#if 0
|
||||||
TEST_F(TorrentMetainfoTest, sanitize)
|
TEST_F(TorrentMetainfoTest, sanitize)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "transmission.h"
|
#include "transmission.h"
|
||||||
|
|
||||||
|
#include "crypto-utils.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "web-utils.h"
|
#include "web-utils.h"
|
||||||
|
|
||||||
|
@ -128,6 +130,18 @@ TEST_F(WebUtilsTest, urlParse)
|
||||||
EXPECT_EQ(8080, parsed->port);
|
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)
|
TEST_F(WebUtilsTest, urlNextQueryPair)
|
||||||
{
|
{
|
||||||
auto constexpr Query = "a=1&b=two&c=si&d_has_no_val&e=&f&g=gee"sv;
|
auto constexpr Query = "a=1&b=two&c=si&d_has_no_val&e=&f&g=gee"sv;
|
||||||
|
|
Loading…
Add table
Reference in a new issue