forked from premiere/premiere-libtorrent
fixed torrent file path vulnerability
This commit is contained in:
parent
d5c8cd5274
commit
eb2203abf5
|
@ -71,6 +71,7 @@ release 0.14.4
|
||||||
* improved handling of out-of-memory conditions in disk I/O thread
|
* improved handling of out-of-memory conditions in disk I/O thread
|
||||||
* fixed bug when force-checking a torrent with partial pieces
|
* fixed bug when force-checking a torrent with partial pieces
|
||||||
* fixed memory leak in disk cache
|
* fixed memory leak in disk cache
|
||||||
|
* fixed torrent file path vulnerability
|
||||||
|
|
||||||
release 0.14.3
|
release 0.14.3
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,16 @@ namespace libtorrent
|
||||||
if (!verify_encoding(p)) target.path = p;
|
if (!verify_encoding(p)) target.path = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool valid_path_element(std::string const& element)
|
||||||
|
{
|
||||||
|
if (element.empty()
|
||||||
|
|| element == "." || element == ".."
|
||||||
|
|| element[0] == '/' || element[0] == '\\'
|
||||||
|
|| element[element.size()-1] == ':')
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void trim_path_element(std::string& path_element)
|
void trim_path_element(std::string& path_element)
|
||||||
{
|
{
|
||||||
#ifdef FILENAME_MAX
|
#ifdef FILENAME_MAX
|
||||||
|
@ -189,6 +199,20 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs::path sanitize_path(fs::path const& p)
|
||||||
|
{
|
||||||
|
fs::path new_path;
|
||||||
|
for (fs::path::const_iterator i = p.begin(); i != p.end(); ++i)
|
||||||
|
{
|
||||||
|
if (!valid_path_element(*i)) continue;
|
||||||
|
std::string pe = *i;
|
||||||
|
trim_path_element(pe);
|
||||||
|
new_path /= pe;
|
||||||
|
}
|
||||||
|
TORRENT_ASSERT(!new_path.is_complete());
|
||||||
|
return new_path;
|
||||||
|
}
|
||||||
|
|
||||||
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
||||||
, std::string const& root_dir)
|
, std::string const& root_dir)
|
||||||
{
|
{
|
||||||
|
@ -215,12 +239,11 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
std::string path_element = p->list_at(i)->string_value();
|
std::string path_element = p->list_at(i)->string_value();
|
||||||
trim_path_element(path_element);
|
trim_path_element(path_element);
|
||||||
if (path_element != "..")
|
target.path /= path_element;
|
||||||
target.path /= path_element;
|
|
||||||
}
|
}
|
||||||
|
target.path = sanitize_path(target.path);
|
||||||
verify_encoding(target);
|
verify_encoding(target);
|
||||||
if (target.path.is_complete())
|
TORRENT_ASSERT(!target.path.is_complete());
|
||||||
return false;
|
|
||||||
|
|
||||||
// bitcomet pad file
|
// bitcomet pad file
|
||||||
if (target.path.string().find("_____padding_file_") != std::string::npos)
|
if (target.path.string().find("_____padding_file_") != std::string::npos)
|
||||||
|
@ -568,34 +591,9 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path tmp = name;
|
name = sanitize_path(name).string();
|
||||||
if (tmp.is_complete())
|
|
||||||
{
|
if (!valid_path_element(name))
|
||||||
name = tmp.leaf();
|
|
||||||
trim_path_element(name);
|
|
||||||
}
|
|
||||||
#if BOOST_VERSION < 103600
|
|
||||||
else if (tmp.has_branch_path())
|
|
||||||
#else
|
|
||||||
else if (tmp.has_parent_path())
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
fs::path p;
|
|
||||||
for (fs::path::iterator i = tmp.begin()
|
|
||||||
, end(tmp.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
if (*i == "." || *i == "..") continue;
|
|
||||||
std::string path_element = *i;
|
|
||||||
trim_path_element(path_element);
|
|
||||||
p /= path_element;
|
|
||||||
}
|
|
||||||
name = p.string();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trim_path_element(name);
|
|
||||||
}
|
|
||||||
if (name == ".." || name == ".")
|
|
||||||
{
|
{
|
||||||
ec = error_code(errors::torrent_invalid_name, libtorrent_category);
|
ec = error_code(errors::torrent_invalid_name, libtorrent_category);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -55,6 +55,10 @@ using namespace libtorrent;
|
||||||
using namespace boost::tuples;
|
using namespace boost::tuples;
|
||||||
using boost::bind;
|
using boost::bind;
|
||||||
|
|
||||||
|
namespace libtorrent {
|
||||||
|
fs::path sanitize_path(fs::path const& p);
|
||||||
|
}
|
||||||
|
|
||||||
sha1_hash to_hash(char const* s)
|
sha1_hash to_hash(char const* s)
|
||||||
{
|
{
|
||||||
sha1_hash ret;
|
sha1_hash ret;
|
||||||
|
@ -355,6 +359,17 @@ int test_main()
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
TEST_CHECK(sanitize_path("/a/b/c").string() == "a/b/c");
|
||||||
|
TEST_CHECK(sanitize_path("a/../c").string() == "a/c");
|
||||||
|
TEST_CHECK(sanitize_path("/.././c").string() == "c");
|
||||||
|
TEST_CHECK(sanitize_path("dev:").string() == "");
|
||||||
|
TEST_CHECK(sanitize_path("c:/b").string() == "b");
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
TEST_CHECK(sanitize_path("c:\\.\\c").string() == "c");
|
||||||
|
#else
|
||||||
|
TEST_CHECK(sanitize_path("//./c").string() == "c");
|
||||||
|
#endif
|
||||||
|
|
||||||
// make sure the time classes have correct semantics
|
// make sure the time classes have correct semantics
|
||||||
|
|
||||||
TEST_CHECK(total_milliseconds(milliseconds(100)) == 100);
|
TEST_CHECK(total_milliseconds(milliseconds(100)) == 100);
|
||||||
|
@ -690,7 +705,7 @@ int test_main()
|
||||||
torrent["info"] = info;
|
torrent["info"] = info;
|
||||||
torrent_info ti2(torrent);
|
torrent_info ti2(torrent);
|
||||||
std::cerr << ti2.name() << std::endl;
|
std::cerr << ti2.name() << std::endl;
|
||||||
TEST_CHECK(ti2.name() == "test3");
|
TEST_CHECK(ti2.name() == "test1/test2/test3");
|
||||||
|
|
||||||
info["name.utf-8"] = "test2/../test3/.././../../test4";
|
info["name.utf-8"] = "test2/../test3/.././../../test4";
|
||||||
torrent["info"] = info;
|
torrent["info"] = info;
|
||||||
|
|
Loading…
Reference in New Issue