mirror of
https://github.com/transmission/transmission
synced 2024-12-24 08:43:27 +00:00
fix: tr_clientForId() (#2887)
* fix: memory corruption when parsing negative numbers * fix: stack-buffer-overflow on escape chars in tr_clientForId * test: add tr_clientForId() fuzz tests
This commit is contained in:
parent
7ff1382503
commit
eb33b2faf5
2 changed files with 146 additions and 30 deletions
|
@ -72,24 +72,112 @@ constexpr std::pair<char*, size_t> buf_append(char* buf, size_t buflen, T t, Arg
|
|||
return buf_append(buf, buflen, args...);
|
||||
}
|
||||
|
||||
// ['0'..'9']: ch - '0'
|
||||
// ['A'..'Z']: 10 + ch - '9'
|
||||
// ['a'..'z']: 36 + ch - '9'
|
||||
auto constexpr charints = std::array<std::string_view, 256>{
|
||||
{ "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "x", "x",
|
||||
"x", "x", "x", "x", "x", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24",
|
||||
"25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "x", "x", "x", "x", "x", "x", "36", "37", "38",
|
||||
"39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58",
|
||||
"59", "60", "61", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
|
||||
"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x" }
|
||||
};
|
||||
constexpr std::string_view charint(char ch)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case '0':
|
||||
return "0"sv;
|
||||
case '1':
|
||||
return "1"sv;
|
||||
case '2':
|
||||
return "2"sv;
|
||||
case '3':
|
||||
return "3"sv;
|
||||
case '4':
|
||||
return "4"sv;
|
||||
case '5':
|
||||
return "5"sv;
|
||||
case '6':
|
||||
return "6"sv;
|
||||
case '7':
|
||||
return "7"sv;
|
||||
case '8':
|
||||
return "8"sv;
|
||||
case '9':
|
||||
return "9"sv;
|
||||
case 'a':
|
||||
case 'A':
|
||||
return "10"sv;
|
||||
case 'b':
|
||||
case 'B':
|
||||
return "11"sv;
|
||||
case 'c':
|
||||
case 'C':
|
||||
return "12"sv;
|
||||
case 'd':
|
||||
case 'D':
|
||||
return "13"sv;
|
||||
case 'e':
|
||||
case 'E':
|
||||
return "14"sv;
|
||||
case 'f':
|
||||
case 'F':
|
||||
return "15"sv;
|
||||
case 'g':
|
||||
case 'G':
|
||||
return "16"sv;
|
||||
case 'h':
|
||||
case 'H':
|
||||
return "17"sv;
|
||||
case 'i':
|
||||
case 'I':
|
||||
return "18"sv;
|
||||
case 'j':
|
||||
case 'J':
|
||||
return "19"sv;
|
||||
case 'k':
|
||||
case 'K':
|
||||
return "20"sv;
|
||||
case 'l':
|
||||
case 'L':
|
||||
return "21"sv;
|
||||
case 'm':
|
||||
case 'M':
|
||||
return "22"sv;
|
||||
case 'n':
|
||||
case 'N':
|
||||
return "23"sv;
|
||||
case 'o':
|
||||
case 'O':
|
||||
return "24"sv;
|
||||
case 'p':
|
||||
case 'P':
|
||||
return "25"sv;
|
||||
case 'q':
|
||||
case 'Q':
|
||||
return "26"sv;
|
||||
case 'r':
|
||||
case 'R':
|
||||
return "27"sv;
|
||||
case 's':
|
||||
case 'S':
|
||||
return "28"sv;
|
||||
case 't':
|
||||
case 'T':
|
||||
return "29"sv;
|
||||
case 'u':
|
||||
case 'U':
|
||||
return "30"sv;
|
||||
case 'v':
|
||||
case 'V':
|
||||
return "31"sv;
|
||||
case 'w':
|
||||
case 'W':
|
||||
return "32"sv;
|
||||
case 'x':
|
||||
case 'X':
|
||||
return "33"sv;
|
||||
case 'y':
|
||||
case 'Y':
|
||||
return "34"sv;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
return "35"sv;
|
||||
default:
|
||||
return "x"sv;
|
||||
}
|
||||
}
|
||||
|
||||
int strint(void const* pch, int span, int base = 0)
|
||||
{
|
||||
|
@ -249,15 +337,15 @@ using format_func = void (*)(char* buf, size_t buflen, std::string_view name, tr
|
|||
|
||||
constexpr void three_digit_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', charints[id[4]], '.', charints[id[5]]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', charint(id[4]), '.', charint(id[5]));
|
||||
}
|
||||
|
||||
constexpr void four_digit_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', charints[id[4]], '.', charints[id[5]], '.', charints[id[6]]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', charint(id[4]), '.', charint(id[5]), '.', charint(id[6]));
|
||||
}
|
||||
|
||||
constexpr void no_version_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t /*id*/)
|
||||
void no_version_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t /*id*/)
|
||||
{
|
||||
buf_append(buf, buflen, name);
|
||||
}
|
||||
|
@ -344,23 +432,23 @@ constexpr void burst_formatter(char* buf, size_t buflen, std::string_view name,
|
|||
|
||||
constexpr void ctorrent_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', charints[id[4]], '.', id[5], id[6]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', charint(id[4]), '.', id[5], id[6]);
|
||||
}
|
||||
|
||||
constexpr void folx_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', 'x');
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', 'x');
|
||||
}
|
||||
|
||||
constexpr void ktorrent_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
if (id[5] == 'D')
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', charints[id[4]], " Dev "sv, charints[id[6]]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', charint(id[4]), " Dev "sv, charint(id[6]));
|
||||
}
|
||||
else if (id[5] == 'R')
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', charints[id[4]], " RC "sv, charints[id[6]]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', charint(id[4]), " RC "sv, charint(id[6]));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -389,7 +477,7 @@ constexpr void mainline_formatter(char* buf, size_t buflen, std::string_view nam
|
|||
|
||||
constexpr void mediaget_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', charints[id[4]]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', charint(id[4]));
|
||||
}
|
||||
|
||||
constexpr void mldonkey_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
|
@ -411,7 +499,7 @@ constexpr void opera_formatter(char* buf, size_t buflen, std::string_view name,
|
|||
|
||||
constexpr void picotorrent_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[3]], '.', id[4], id[5], '.', charints[id[6]]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[3]), '.', id[4], id[5], '.', charint(id[6]));
|
||||
}
|
||||
|
||||
constexpr void plus_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
|
@ -421,7 +509,7 @@ constexpr void plus_formatter(char* buf, size_t buflen, std::string_view name, t
|
|||
|
||||
constexpr void qvod_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
buf_append(buf, buflen, name, ' ', charints[id[4]], '.', charints[id[5]], '.', charints[id[6]], '.', charints[id[7]]);
|
||||
buf_append(buf, buflen, name, ' ', charint(id[4]), '.', charint(id[5]), '.', charint(id[6]), '.', charint(id[7]));
|
||||
}
|
||||
|
||||
void transmission_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
|
@ -500,7 +588,7 @@ constexpr void xfplay_formatter(char* buf, size_t buflen, std::string_view name,
|
|||
|
||||
void xtorrent_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
|
||||
{
|
||||
std::tie(buf, buflen) = buf_append(buf, buflen, name, ' ', charints[id[3]], '.', charints[id[4]], " ("sv);
|
||||
std::tie(buf, buflen) = buf_append(buf, buflen, name, ' ', charint(id[3]), '.', charint(id[4]), " ("sv);
|
||||
*fmt::format_to_n(buf, buflen - 1, FMT_STRING("{:d}"), strint(&id[5], 2)).out = '\0';
|
||||
}
|
||||
|
||||
|
@ -699,7 +787,7 @@ char* tr_clientForId(char* buf, size_t buflen, tr_peer_id_t peer_id)
|
|||
}
|
||||
else
|
||||
{
|
||||
walk = fmt::format_to_n(walk, end - walk - 1, FMT_STRING("%{:02X}"), unsigned(c)).out;
|
||||
walk = fmt::format_to_n(walk, end - walk - 1, FMT_STRING("%{:02X}"), static_cast<unsigned char>(c)).out;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,3 +74,31 @@ TEST(Client, clientForId)
|
|||
EXPECT_EQ(test.expected_client, std::string_view{ buf.data() });
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Client, fuzzRegressions)
|
||||
{
|
||||
auto constexpr Tests = std::array<std::string_view, 5>{
|
||||
"LVJTp3u+Aptl01HjzTHXVC5b9g4="sv, "LWJrHb2OpoNsJdODHA7iyXjnHxc="sv, "LU1PjpTjmvUth+f15YTOOggXl3k="sv,
|
||||
"LUxU1gO7xhfBD4bmyZkB+neZIx0="sv, "LVJTp3u+Aptl01HjzTHXVC5b9g4="sv,
|
||||
};
|
||||
|
||||
for (auto const& test : Tests)
|
||||
{
|
||||
auto const input = tr_base64_decode(test);
|
||||
auto peer_id = tr_peer_id_t{};
|
||||
std::copy(std::begin(input), std::end(input), std::begin(peer_id));
|
||||
auto buf = std::array<char, 128>{};
|
||||
tr_clientForId(buf.data(), buf.size(), peer_id);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Client, fuzz)
|
||||
{
|
||||
for (size_t i = 0; i < 10000; ++i)
|
||||
{
|
||||
auto peer_id = tr_peer_id_t{};
|
||||
tr_rand_buffer(std::data(peer_id), std::size(peer_id));
|
||||
auto buf = std::array<char, 128>{};
|
||||
tr_clientForId(buf.data(), buf.size(), peer_id);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue