fix: crash when magnet dn isn't utf-8 (#5244)

This commit is contained in:
Cœur 2023-03-19 23:36:16 +08:00 committed by GitHub
parent ca44c9143a
commit c60bb5b834
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 9 deletions

View File

@ -402,6 +402,7 @@
C809AEE7291ECFD000BFDBE1 /* NSDataAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C809AEE6291ECFD000BFDBE1 /* NSDataAdditions.mm */; };
C82B30312953337B0001BD6E /* NSDataAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C809AEE6291ECFD000BFDBE1 /* NSDataAdditions.mm */; };
C841A28129197724009F18E8 /* NSKeyedUnarchiverAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = C841A28029197724009F18E8 /* NSKeyedUnarchiverAdditions.mm */; };
C843FC8429C51B9400491854 /* utils.mm in Sources */ = {isa = PBXBuildFile; fileRef = C843FC8329C51B9400491854 /* utils.mm */; };
C86BCD9928228A9600F45599 /* SparkleProxy.mm in Sources */ = {isa = PBXBuildFile; fileRef = C86BCD9828228A9600F45599 /* SparkleProxy.mm */; };
C87369652809984200573C90 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C87369642809984200573C90 /* UserNotifications.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
C8748D8A29891EA100D9E979 /* suffixes_dafsa.h in Headers */ = {isa = PBXBuildFile; fileRef = C8748D8929891EA100D9E979 /* suffixes_dafsa.h */; };
@ -1207,6 +1208,7 @@
C81E411127F5BABD00652F56 /* CocoaCompatibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CocoaCompatibility.h; sourceTree = "<group>"; };
C841A27F29197724009F18E8 /* NSKeyedUnarchiverAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSKeyedUnarchiverAdditions.h; sourceTree = "<group>"; };
C841A28029197724009F18E8 /* NSKeyedUnarchiverAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = NSKeyedUnarchiverAdditions.mm; sourceTree = "<group>"; };
C843FC8329C51B9400491854 /* utils.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = utils.mm; sourceTree = "<group>"; };
C86BCD9828228A9600F45599 /* SparkleProxy.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SparkleProxy.mm; sourceTree = "<group>"; };
C87369642809984200573C90 /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
C8748D8929891EA100D9E979 /* suffixes_dafsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = suffixes_dafsa.h; path = "third-party/suffixes_dafsa.h"; sourceTree = SOURCE_ROOT; };
@ -1793,6 +1795,7 @@
BEFC1DF30C07861A00B0BB3C /* port-forwarding-upnp.h */,
BEFC1DF20C07861A00B0BB3C /* utils.cc */,
BEFC1DF10C07861A00B0BB3C /* utils.h */,
C843FC8329C51B9400491854 /* utils.mm */,
A25BFD63167BED3B0039D1AA /* variant-benc.cc */,
A25BFD64167BED3B0039D1AA /* variant-common.h */,
A25BFD65167BED3B0039D1AA /* variant-json.cc */,
@ -3082,6 +3085,7 @@
A220EC5B118C8A060022B4BE /* tr-lpd.cc in Sources */,
C1FEE57A1C3223CC00D62832 /* watchdir.cc in Sources */,
A23547E211CD0B090046EAE6 /* cache.cc in Sources */,
C843FC8429C51B9400491854 /* utils.mm in Sources */,
A284214412DA663E00FBDDBB /* tr-udp.cc in Sources */,
C17740D5273A002C00E455D2 /* web-utils.cc in Sources */,
A2679294130E00A000CB7464 /* tr-utp.cc in Sources */,

View File

@ -150,6 +150,7 @@ target_sources(${TR_NAME}
utils-ev.h
utils.cc
utils.h
utils.mm
variant-benc.cc
variant-common.h
variant-converters.cc
@ -198,6 +199,7 @@ tr_allow_compile_if(
watchdir-kqueue.cc
[=[[APPLE]]=]
tr-assert.mm
utils.mm
[=[[NOT APPLE]]=]
tr-assert.cc
[=[[WIN32]]=]

View File

@ -14,6 +14,7 @@
#include "announce-list.h"
#include "tr-strbuf.h" // tr_urlbuf
#include "utils.h" // tr_strv_convert_utf8()
struct tr_error;
struct tr_variant;
@ -69,7 +70,7 @@ public:
void setName(std::string_view name)
{
name_ = name;
name_ = tr_strv_convert_utf8(name);
}
void addWebseed(std::string_view webseed);

View File

@ -329,11 +329,11 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
}
else if (pathIs(CommentKey) || pathIs(CommentUtf8Key))
{
tm_.comment_ = tr_strv_replace_invalid(value);
tm_.comment_ = tr_strv_convert_utf8(value);
}
else if (pathIs(CreatedByKey) || pathIs(CreatedByUtf8Key))
{
tm_.creator_ = tr_strv_replace_invalid(value);
tm_.creator_ = tr_strv_convert_utf8(value);
}
else if (
pathIs(SourceKey) || pathIs(InfoKey, SourceKey) || //
@ -344,7 +344,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
// to have the same use as the 'source' key
// http://wiki.bitcomet.com/inside_bitcomet
tm_.source_ = tr_strv_replace_invalid(value);
tm_.source_ = tr_strv_convert_utf8(value);
}
else if (pathIs(AnnounceKey))
{
@ -360,7 +360,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
}
else if (pathIs(InfoKey, NameKey) || pathIs(InfoKey, NameUtf8Key))
{
tm_.name_ = tr_strv_replace_invalid(value);
tm_.setName(value);
}
else if (pathIs(InfoKey, PiecesKey))
{
@ -393,7 +393,7 @@ struct MetainfoHandler final : public transmission::benc::BasicHandler<MaxBencDe
else if (pathIs(MagnetInfoKey, DisplayNameKey))
{
// compatibility with Transmission <= 3.0
tm_.name_ = tr_strv_replace_invalid(value);
tm_.setName(value);
}
else if (pathIs(MagnetInfoKey, InfoHashKey))
{

View File

@ -268,9 +268,24 @@ double tr_getRatio(uint64_t numerator, uint64_t denominator)
// ---
#ifndef __APPLE__
std::string tr_strv_convert_utf8(std::string_view sv)
{
return tr_strv_replace_invalid(sv);
}
#endif
std::string tr_strv_replace_invalid(std::string_view sv, uint32_t replacement)
{
// stripping characters after first \0
if (auto first_null = sv.find('\0'); first_null != std::string::npos)
{
sv = { std::data(sv), first_null };
}
auto out = std::string{};
out.reserve(std::size(sv));
utf8::unchecked::replace_invalid(std::data(sv), std::data(sv) + std::size(sv), std::back_inserter(out), replacement);
return out;
}

View File

@ -204,6 +204,8 @@ constexpr bool tr_strvSep(std::string_view* sv, std::string_view* token, char de
[[nodiscard]] std::string_view tr_strvStrip(std::string_view str);
[[nodiscard]] std::string tr_strv_convert_utf8(std::string_view sv);
[[nodiscard]] std::string tr_strv_replace_invalid(std::string_view sv, uint32_t replacement = 0xFFFD /*<2A>*/);
/**

49
libtransmission/utils.mm Normal file
View File

@ -0,0 +1,49 @@
// This file Copyright © 2022-2023 Mnemosyne LLC.
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#import <Foundation/Foundation.h>
#include <string>
#include <string_view>
#include "utils.h"
// macOS implementation of tr_strv_convert_utf8() that autodetects the encoding.
// This replaces the generic implementation of the function in utils.cc.
std::string tr_strv_convert_utf8(std::string_view sv)
{
// UTF-8 encoding
char const* validUTF8 = [[NSString alloc] initWithBytes:std::data(sv) length:std::size(sv) encoding:NSUTF8StringEncoding].UTF8String;
if (validUTF8)
{
return std::string(validUTF8);
}
// autodetection of the encoding (#3434)
NSString* convertedString;
NSStringEncoding stringEncoding = [NSString
stringEncodingForData:[NSData dataWithBytes:std::data(sv) length:std::size(sv)]
encodingOptions:@{
// We disallow lossy conversion, and will leave it to `utf8::unchecked::replace_invalid`.
NSStringEncodingDetectionAllowLossyKey : @NO,
// We only set the likely language.
// If we were to set suggested encodings, then whatever is listed first would take precedence on all others, making for instance kCFStringEncodingDOSJapanese (cp932) and kCFStringEncodingDOSRussian (cp866) taking priority on each other.
NSStringEncodingDetectionLikelyLanguageKey : NSLocale.currentLocale.languageCode
}
convertedString:&convertedString
usedLossyConversion:nil];
if (stringEncoding)
{
validUTF8 = convertedString.UTF8String;
if (validUTF8)
{
return std::string(validUTF8);
}
}
// invalid encoding
return tr_strv_replace_invalid(sv);
}

View File

@ -151,15 +151,15 @@ TEST_F(UtilsTest, strvReplaceInvalid)
EXPECT_EQ(out, tr_strv_replace_invalid(out));
}
TEST_F(UtilsTest, strvReplaceInvalidFuzz)
TEST_F(UtilsTest, strvConvertUtf8Fuzz)
{
auto buf = std::vector<char>{};
for (size_t i = 0; i < 1000; ++i)
{
buf.resize(tr_rand_int(4096U));
tr_rand_buffer(std::data(buf), std::size(buf));
auto const out = tr_strv_replace_invalid({ std::data(buf), std::size(buf) });
EXPECT_EQ(out, tr_strv_replace_invalid(out));
auto const out = tr_strv_convert_utf8({ std::data(buf), std::size(buf) });
EXPECT_EQ(out, tr_strv_convert_utf8(out));
}
}