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
|
||||
* fixed bug when force-checking a torrent with partial pieces
|
||||
* fixed memory leak in disk cache
|
||||
* fixed torrent file path vulnerability
|
||||
|
||||
release 0.14.3
|
||||
|
||||
|
|
|
@ -163,6 +163,16 @@ namespace libtorrent
|
|||
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)
|
||||
{
|
||||
#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
|
||||
, std::string const& root_dir)
|
||||
{
|
||||
|
@ -215,12 +239,11 @@ namespace libtorrent
|
|||
return false;
|
||||
std::string path_element = p->list_at(i)->string_value();
|
||||
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);
|
||||
if (target.path.is_complete())
|
||||
return false;
|
||||
TORRENT_ASSERT(!target.path.is_complete());
|
||||
|
||||
// bitcomet pad file
|
||||
if (target.path.string().find("_____padding_file_") != std::string::npos)
|
||||
|
@ -568,34 +591,9 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
fs::path tmp = name;
|
||||
if (tmp.is_complete())
|
||||
{
|
||||
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 == ".")
|
||||
name = sanitize_path(name).string();
|
||||
|
||||
if (!valid_path_element(name))
|
||||
{
|
||||
ec = error_code(errors::torrent_invalid_name, libtorrent_category);
|
||||
return false;
|
||||
|
|
|
@ -55,6 +55,10 @@ using namespace libtorrent;
|
|||
using namespace boost::tuples;
|
||||
using boost::bind;
|
||||
|
||||
namespace libtorrent {
|
||||
fs::path sanitize_path(fs::path const& p);
|
||||
}
|
||||
|
||||
sha1_hash to_hash(char const* s)
|
||||
{
|
||||
sha1_hash ret;
|
||||
|
@ -355,6 +359,17 @@ int test_main()
|
|||
{
|
||||
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
|
||||
|
||||
TEST_CHECK(total_milliseconds(milliseconds(100)) == 100);
|
||||
|
@ -690,7 +705,7 @@ int test_main()
|
|||
torrent["info"] = info;
|
||||
torrent_info ti2(torrent);
|
||||
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";
|
||||
torrent["info"] = info;
|
||||
|
|
Loading…
Reference in New Issue