fixup! refactor: add tr_peer_id_t (#2004) (#2016)

fix: array bounds read error introduced yesterday
This commit is contained in:
Charles Kerr 2021-10-22 15:24:30 -05:00 committed by GitHub
parent 0c39924074
commit 94ee81f98d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 107 deletions

View File

@ -120,13 +120,13 @@ constexpr std::string_view getMnemonicEnd(uint8_t ch)
}
}
void two_major_two_minor_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
void two_major_two_minor_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
std::tie(buf, buflen) = buf_append(buf, buflen, name, ' ', strint(id + 3, 2), '.');
tr_snprintf(buf, buflen, "%02d", strint(id + 5, 2));
std::tie(buf, buflen) = buf_append(buf, buflen, name, ' ', strint(&id[3], 2), '.');
tr_snprintf(buf, buflen, "%02d", strint(&id[5], 2));
}
bool decodeShad0wClient(char* buf, size_t buflen, std::string_view peer_id)
bool decodeShad0wClient(char* buf, size_t buflen, std::string_view in)
{
// Shad0w with his experimental BitTorrent implementation and BitTornado
// introduced peer ids that begin with a character which is``T`` in the
@ -143,6 +143,8 @@ bool decodeShad0wClient(char* buf, size_t buflen, std::string_view peer_id)
return pos != std::string_view::npos ? pos : std::optional<int>{};
};
auto peer_id = std::string_view{ std::data(in), 9 };
if (std::size(peer_id) != 9 || peer_id[6] != '-' || peer_id[7] != '-' || peer_id[8] != '-')
{
return false;
@ -238,31 +240,31 @@ bool decodeBitCometClient(char* buf, size_t buflen, std::string_view peer_id)
return true;
}
using format_func = void (*)(char* buf, size_t buflen, std::string_view name, char const* id);
using format_func = void (*)(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id);
constexpr void three_digit_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
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]]);
}
constexpr void four_digit_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
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]]);
}
constexpr void no_version_formatter(char* buf, size_t buflen, std::string_view name, [[maybe_unused]] char const* id)
constexpr void no_version_formatter(char* buf, size_t buflen, std::string_view name, [[maybe_unused]] tr_peer_id_t id)
{
buf_append(buf, buflen, name);
}
// specific clients
constexpr void amazon_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void amazon_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', id[3], '.', id[5], '.', id[7]);
}
constexpr void aria2_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void aria2_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
if (id[4] == '-' && id[6] == '-' && id[8] == '-')
{
@ -278,28 +280,28 @@ constexpr void aria2_formatter(char* buf, size_t buflen, std::string_view name,
}
}
constexpr void bitbuddy_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void bitbuddy_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', id[3], '.', id[4], id[5], id[6]);
}
constexpr void bitlord_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void bitlord_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', id[3], '.', id[4], '.', id[5], '-', std::string_view(id + 6, 3));
buf_append(buf, buflen, name, ' ', id[3], '.', id[4], '.', id[5], '-', std::string_view(&id[6], 3));
}
constexpr void bitrocket_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void bitrocket_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', id[3], '.', id[4], ' ', '(', id[5], id[6], ')');
}
void bittorrent_dna_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
void bittorrent_dna_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
std::tie(buf, buflen) = buf_append(buf, buflen, name, ' ');
tr_snprintf(buf, buflen, "%d.%d.%d", strint(id + 3, 2), strint(id + 5, 2), strint(id + 7, 2));
tr_snprintf(buf, buflen, "%d.%d.%d", strint(&id[3], 2), strint(&id[5], 2), strint(&id[7], 2));
}
void bits_on_wheels_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
void bits_on_wheels_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
// Bits on Wheels uses the pattern -BOWxxx-yyyyyyyyyyyy, where y is random
// (uppercase letters) and x depends on the version.
@ -319,32 +321,32 @@ void bits_on_wheels_formatter(char* buf, size_t buflen, std::string_view name, c
}
}
constexpr void blizzard_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void blizzard_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', int(id[3] + 1), int(id[4]));
}
constexpr void btpd_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void btpd_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', std::string_view(id + 5, 3));
buf_append(buf, buflen, name, ' ', std::string_view(&id[5], 3));
}
constexpr void burst_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void burst_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', id[5], '.', id[7], '.', id[9]);
}
constexpr void ctorrent_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
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]);
}
constexpr void folx_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
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');
}
constexpr void ktorrent_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void ktorrent_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
if (id[5] == 'D')
{
@ -360,7 +362,7 @@ constexpr void ktorrent_formatter(char* buf, size_t buflen, std::string_view nam
}
}
constexpr void mainline_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void mainline_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
// Queen Bee uses Bram`s new style:
// Q1-0-0-- or Q1-10-0- followed by random bytes.
@ -379,68 +381,62 @@ 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, char const* id)
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]]);
}
constexpr void mldonkey_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void mldonkey_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
// MLdonkey use the following peer_id scheme: the first characters are
// -ML followed by a dotted version then a - followed by randomness.
// e.g. -ML2.7.2-kgjjfkd
buf_append(buf, buflen, name, ' ', std::string_view(id + 3, 5));
buf_append(buf, buflen, name, ' ', std::string_view(&id[3], 5));
}
constexpr void opera_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void opera_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
// Opera 8 previews and Opera 9.x releases use the following peer_id
// scheme: The first two characters are OP and the next four digits equal
// the build number. All following characters are random lowercase
// hexdecimal digits.
buf_append(buf, buflen, name, ' ', std::string_view(id + 2, 4));
buf_append(buf, buflen, name, ' ', std::string_view(&id[2], 4));
}
constexpr void picotorrent_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
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]]);
}
constexpr void plus_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void plus_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', id[4], '.', id[5], id[6]);
}
constexpr void qvod_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void qvod_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
four_digit_formatter(buf, buflen, name, id + 1);
buf_append(buf, buflen, name, ' ', charints[id[4]], '.', charints[id[5]], '.', charints[id[6]], '.', charints[id[7]]);
}
void transmission_formatter(char* buf, size_t buflen, std::string_view name, char const* chid)
void transmission_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
std::tie(buf, buflen) = buf_append(buf, buflen, name, ' ');
if (strncmp(chid + 3, "000", 3) == 0) // very old client style: -TR0006- is 0.6
if (strncmp(&id[3], "000", 3) == 0) // very old client style: -TR0006- is 0.6
{
tr_snprintf(buf, buflen, "0.%c", chid[6]);
tr_snprintf(buf, buflen, "0.%c", id[6]);
}
else if (strncmp(chid + 3, "00", 2) == 0) // previous client style: -TR0072- is 0.72
else if (strncmp(&id[3], "00", 2) == 0) // previous client style: -TR0072- is 0.72
{
tr_snprintf(buf, buflen, "0.%02d", strint(chid + 5, 2));
tr_snprintf(buf, buflen, "0.%02d", strint(&id[5], 2));
}
else // current client style: -TR111Z- is 1.11+ */
{
tr_snprintf(
buf,
buflen,
"%d.%02d%s",
strint(chid + 3, 1),
strint(chid + 4, 2),
(chid[6] == 'Z' || chid[6] == 'X') ? "+" : "");
tr_snprintf(buf, buflen, "%d.%02d%s", strint(&id[3], 1), strint(&id[4], 2), (id[6] == 'Z' || id[6] == 'X') ? "+" : "");
}
}
constexpr void utorrent_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void utorrent_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
if (id[7] == '-')
{
@ -452,12 +448,12 @@ constexpr void utorrent_formatter(char* buf, size_t buflen, std::string_view nam
}
}
constexpr void xbt_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void xbt_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
buf_append(buf, buflen, name, ' ', id[3], '.', id[4], '.', id[5], getMnemonicEnd(id[6]));
}
constexpr void xfplay_formatter(char* buf, size_t buflen, std::string_view name, char const* id)
constexpr void xfplay_formatter(char* buf, size_t buflen, std::string_view name, tr_peer_id_t id)
{
if (id[6] == '0')
{
@ -469,10 +465,10 @@ 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, char const* id)
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);
tr_snprintf(buf, buflen, "%d)", strint(id + 5, 2));
tr_snprintf(buf, buflen, "%d)", strint(&id[5], 2));
}
struct Client
@ -614,26 +610,20 @@ auto constexpr Clients = std::array<Client, 127>{ {
} // namespace
char* tr_clientForId(char* buf, size_t buflen, void const* id_in)
char* tr_clientForId(char* buf, size_t buflen, tr_peer_id_t peer_id)
{
*buf = '\0';
auto const* const id = static_cast<char const*>(id_in);
if (id == nullptr)
{
return buf;
}
auto const key = std::string_view{ id };
auto const key = std::string_view{ std::data(peer_id), std::size(peer_id) };
if (decodeShad0wClient(buf, buflen, key) || decodeBitCometClient(buf, buflen, key))
{
return buf;
}
if (!*id && strncmp(id + 2, "BS", 2) == 0)
if (peer_id[0] == '\0' && peer_id[2] == 'B' && peer_id[3] == 'S')
{
tr_snprintf(buf, buflen, "BitSpirit %d", id[1] == '\0' ? 1 : int(id[1]));
tr_snprintf(buf, buflen, "BitSpirit %d", peer_id[1] == '\0' ? 1 : int(peer_id[1]));
return buf;
}
@ -654,7 +644,7 @@ char* tr_clientForId(char* buf, size_t buflen, void const* id_in)
auto eq = std::equal_range(std::begin(Clients), std::end(Clients), key, Compare{});
if (eq.first != std::end(Clients) && eq.first != eq.second)
{
eq.first->formatter(buf, buflen, eq.first->name, id);
eq.first->formatter(buf, buflen, eq.first->name, peer_id);
return buf;
}
@ -668,7 +658,7 @@ char* tr_clientForId(char* buf, size_t buflen, void const* id_in)
for (size_t i = 0; i < 8; ++i)
{
char const c = id[i];
char const c = peer_id[i];
if (isprint((unsigned char)c))
{

View File

@ -18,4 +18,4 @@
* @brief parse a peer-id into a human-readable client name and version number
* @ingroup utils
*/
char* tr_clientForId(char* buf, size_t buflen, void const* peer_id);
char* tr_clientForId(char* buf, size_t buflen, tr_peer_id_t peer_id);

View File

@ -703,7 +703,7 @@ static ReadState readPeerId(tr_handshake* handshake, struct evbuffer* inbuf)
handshake->peer_id = peer_id;
char client[128] = {};
tr_clientForId(client, sizeof(client), std::data(peer_id));
tr_clientForId(client, sizeof(client), peer_id);
dbgmsg(handshake, "peer-id is [%s] ... isIncoming is %d", client, tr_peerIoIsIncoming(handshake->io));
// if we've somehow connected to ourselves, don't keep the connection

View File

@ -2018,7 +2018,7 @@ static bool on_handshake_done(tr_handshake_result const& result)
if (result.peer_id)
{
char buf[128] = {};
tr_clientForId(buf, sizeof(buf), std::data(*result.peer_id));
tr_clientForId(buf, sizeof(buf), *result.peer_id);
client = tr_quark_new(buf);
}

View File

@ -7,64 +7,72 @@
*/
#include <array>
#include <string_view>
#include "transmission.h"
#include "clients.h"
#include "crypto-utils.h"
#include "gtest/gtest.h"
using namespace std::literals;
TEST(Client, clientForId)
{
struct LocalTest
{
char const* peer_id;
char const* expected_client;
std::string_view peer_id;
std::string_view expected_client;
};
auto constexpr Tests = std::array<LocalTest, 37>{
{ { "-AZ8421-", "Azureus / Vuze 8.4.2.1" },
{ "-BC0241-", "BitComet 2.41" }, // two major, two minor
{ "-BI2300-", "BiglyBT 2.3.0.0" },
{ "-BL246326", "BitLord 2.4.6-326" }, // Style used after BitLord 0.59
{ "-BN0001-", "Baidu Netdisk" }, // Baidu Netdisk Client v5.5.4
{ "-BT791B-", "BitTorrent 7.9.1 (Beta)" },
{ "-BT791\0-", "BitTorrent 7.9.1" },
{ "-FC1013-", "FileCroc 1.0.1.3" },
{ "-FC1013-", "FileCroc 1.0.1.3" },
{ "-FD51@\xFF-", "Free Download Manager 5.1.x" }, // Negative test case
{ "-FD51R\xFF-", "Free Download Manager 5.1.27" },
{ "-FD51W\xFF-", "Free Download Manager 5.1.32" },
{ "-FL51FF-", "Folx 5.x" }, // Folx v5.2.1.13690
{ "-FW6830-", "FrostWire 6.8.3" },
{ "-IIO\x10\x2D\x04-", "-IIO%10-%04-" },
{ "-I\05O\x08\x03\x01-", "-I%05O%08%03%01-" },
{ "-KT33D1-", "KTorrent 3.3 Dev 1" },
{ "-MR1100-", "Miro 1.1.0.0" },
{ "-PI0091-", "PicoTorrent 0.09.1" },
{ "-PI0120-", "PicoTorrent 0.12.0" },
{ "-TR0006-", "Transmission 0.6" },
{ "-TR0072-", "Transmission 0.72" },
{ "-TR111Z-", "Transmission 1.11+" },
{ "-UT341\0-", "\xc2\xb5Torrent 3.4.1" },
{ "-UW110Q-", "\xc2\xb5Torrent Web 1.1.0" },
{ "-UW1110Q", "\xc2\xb5Torrent Web 1.1.10" }, // wider version
{ "-WS1000-", "HTTP Seed" },
{ "-WW0007-", "WebTorrent 0.0.0.7" },
{ "-XF9990-", "Xfplay 9.9.9" }, // Older Xfplay versions have three digit version number
{ "-XF9992-", "Xfplay 9.9.92" }, // Xfplay 9.9.92 to 9.9.94 uses "-XF9992-"
{ "A2-1-18-8-", "aria2 1.18.8" },
{ "A2-1-2-0-", "aria2 1.2.0" },
{ "S58B-----", "Shad0w 5.8.11" },
{ "Q1-23-4-", "Queen Bee 1.23.4" },
{ "TIX0193-", "Tixati 1.93" },
{ "\x65\x78\x62\x63\x00\x38\x4C\x4F\x52\x44\x32\x00\x04\x8E\xCE\xD5\x7B\xD7\x10\x28", "BitLord 0.56" },
{ "\x65\x78\x62\x63\x00\x38\x7A\x44\x63\x10\x2D\x6E\x9A\xD6\x72\x3B\x33\x9F\x35\xA9", "BitComet 0.56" } }
{ { "-AZ8421-"sv, "Azureus / Vuze 8.4.2.1"sv },
{ "-BC0241-"sv, "BitComet 2.41"sv }, // two major, two minor
{ "-BI2300-"sv, "BiglyBT 2.3.0.0"sv },
{ "-BL246326"sv, "BitLord 2.4.6-326"sv }, // Style used after BitLord 0.59
{ "-BN0001-"sv, "Baidu Netdisk"sv }, // Baidu Netdisk Client v5.5.4
{ "-BT791B-"sv, "BitTorrent 7.9.1 (Beta)"sv },
{ "-BT791\0-"sv, "BitTorrent 7.9.1"sv },
{ "-FC1013-"sv, "FileCroc 1.0.1.3"sv },
{ "-FC1013-"sv, "FileCroc 1.0.1.3"sv },
{ "-FD51@\xFF-"sv, "Free Download Manager 5.1.x"sv }, // Negative test case
{ "-FD51R\xFF-"sv, "Free Download Manager 5.1.27"sv },
{ "-FD51W\xFF-"sv, "Free Download Manager 5.1.32"sv },
{ "-FL51FF-"sv, "Folx 5.x"sv }, // Folx v5.2.1.13690
{ "-FW6830-"sv, "FrostWire 6.8.3"sv },
{ "-IIO\x10\x2D\x04-"sv, "-IIO%10-%04-"sv },
{ "-I\05O\x08\x03\x01-"sv, "-I%05O%08%03%01-"sv },
{ "-KT33D1-"sv, "KTorrent 3.3 Dev 1"sv },
{ "-MR1100-"sv, "Miro 1.1.0.0"sv },
{ "-PI0091-"sv, "PicoTorrent 0.09.1"sv },
{ "-PI0120-"sv, "PicoTorrent 0.12.0"sv },
{ "-TR0006-"sv, "Transmission 0.6"sv },
{ "-TR0072-"sv, "Transmission 0.72"sv },
{ "-TR111Z-"sv, "Transmission 1.11+"sv },
{ "-UT341\0-"sv, "\xc2\xb5Torrent 3.4.1"sv },
{ "-UW110Q-"sv, "\xc2\xb5Torrent Web 1.1.0"sv },
{ "-UW1110Q"sv, "\xc2\xb5Torrent Web 1.1.10"sv }, // wider version
{ "-WS1000-"sv, "HTTP Seed"sv },
{ "-WW0007-"sv, "WebTorrent 0.0.0.7"sv },
{ "-XF9990-"sv, "Xfplay 9.9.9"sv }, // Older Xfplay versions have three digit version number
{ "-XF9992-"sv, "Xfplay 9.9.92"sv }, // Xfplay 9.9.92 to 9.9.94 uses "-XF9992-"
{ "A2-1-18-8-"sv, "aria2 1.18.8"sv },
{ "A2-1-2-0-"sv, "aria2 1.2.0"sv },
{ "S58B-----"sv, "Shad0w 5.8.11"sv },
{ "Q1-23-4-"sv, "Queen Bee 1.23.4"sv },
{ "TIX0193-"sv, "Tixati 1.93"sv },
{ "\x65\x78\x62\x63\x00\x38\x4C\x4F\x52\x44\x32\x00\x04\x8E\xCE\xD5\x7B\xD7\x10\x28"sv, "BitLord 0.56"sv },
{ "\x65\x78\x62\x63\x00\x38\x7A\x44\x63\x10\x2D\x6E\x9A\xD6\x72\x3B\x33\x9F\x35\xA9"sv, "BitComet 0.56"sv } }
};
for (auto const& test : Tests)
{
auto peer_id = tr_peer_id_t{};
tr_rand_buffer(std::data(peer_id), std::size(peer_id));
std::copy(std::begin(test.peer_id), std::end(test.peer_id), std::begin(peer_id));
auto buf = std::array<char, 128>{};
tr_clientForId(buf.data(), buf.size(), test.peer_id);
EXPECT_STREQ(test.expected_client, buf.data());
tr_clientForId(buf.data(), buf.size(), peer_id);
EXPECT_EQ(test.expected_client, buf.data());
}
}