fix: fail if pieces length in info dict is not multiple of 20 (#8412)

* fix: fail if `pieces` length in info dict is not multiple of 20

* fix(tests): replace potentially malicious test torrent for pieces length

(cherry picked from commit 182c8ce12c)
This commit is contained in:
Yat Ho
2026-02-10 11:38:21 +08:00
committed by GitHub
parent 582668cf08
commit 3d8363a8d4
3 changed files with 15 additions and 11 deletions

View File

@@ -364,17 +364,16 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
}
else if (pathIs(InfoKey, PiecesKey))
{
if (std::size(value) % sizeof(tr_sha1_digest_t) == 0)
static auto constexpr Sha1Len = std::tuple_size_v<tr_sha1_digest_t>;
auto const len = std::size(value);
if (len % Sha1Len != 0U)
{
auto const n = std::size(value) / sizeof(tr_sha1_digest_t);
tm_.pieces_.resize(n);
std::copy_n(std::data(value), std::size(value), reinterpret_cast<char*>(std::data(tm_.pieces_)));
}
else
{
context.error.set(EINVAL, fmt::format("invalid piece size: {}", std::size(value)));
unhandled = true;
context.error.set(EINVAL, fmt::format("invalid 'pieces' size: {}", len));
return false;
}
tm_.pieces_.resize(len / Sha1Len);
std::copy_n(std::data(value), len, reinterpret_cast<char*>(std::data(tm_.pieces_)));
}
else if (pathStartsWith(PieceLayersKey))
{

View File

@@ -0,0 +1 @@
d8:announce28:https://example.com/announce8:checksum64:78d16df696e22610ab7c2e10a335a6b2543eaa8c10508a36b9760c69cdb3fb557:comment14:sample torrent10:created by13:uTorrent/204013:creation datei1317056433e8:encoding5:UTF-84:infod5:filesld6:lengthi8388608e4:pathl9:file1.txteed6:lengthi8388608e4:pathl9:file2.mkveed6:lengthi8388608e4:pathl9:file3.nfoeee4:name15:ThisIsMyTorrent12:piece lengthi4194304e6:pieces119:+ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª7:privatei1e6:source15:Example Trackeree

View File

@@ -206,10 +206,14 @@ TEST_F(TorrentMetainfoTest, GetRightStyleWebseedString)
}
// Test for https://github.com/transmission/transmission/issues/3591
TEST_F(TorrentMetainfoTest, parseBencOOBWrite)
TEST_F(TorrentMetainfoTest, parseBencPiecesSize)
{
auto const src_filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/invalid-pieces-length.torrent"sv };
auto error = tr_error{};
auto tm = tr_torrent_metainfo{};
EXPECT_FALSE(tm.parse_benc(tr_base64_decode("ZGg0OmluZm9kNjpwaWVjZXMzOkFpzQ==")));
EXPECT_FALSE(tm.parse_torrent_file(src_filename, nullptr, &error));
EXPECT_EQ(error.code(), EINVAL);
EXPECT_EQ(error.message(), "invalid 'pieces' size: 119"sv);
}
} // namespace libtransmission::test