From 21fef88928ea9ba5b1e0ca62421187e217ee2212 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 1 Oct 2017 04:30:32 +0200 Subject: [PATCH] stricten up the filename sanitization a bit --- src/file_storage.cpp | 1 + src/torrent_info.cpp | 33 +++++++++++--------- test/test_torrent_info.cpp | 7 +++++ test/test_torrents/absolute_filename.torrent | 1 + 4 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 test/test_torrents/absolute_filename.torrent diff --git a/src/file_storage.cpp b/src/file_storage.cpp index c258b0497..48144216c 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -571,6 +571,7 @@ namespace { , std::int64_t const mtime, string_view symlink_path) { TORRENT_ASSERT_PRECOND(file_size >= 0); + TORRENT_ASSERT_PRECOND(!is_complete(filename)); if (!has_parent_path(path)) { // you have already added at least one file with a diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 3dbe11542..ee55fd179 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -176,9 +176,9 @@ namespace libtorrent { if (element.size() == 1 && element[0] == '.') return; #ifdef TORRENT_WINDOWS -#define TORRENT_SEPARATOR "\\" +#define TORRENT_SEPARATOR '\\' #else -#define TORRENT_SEPARATOR "/" +#define TORRENT_SEPARATOR '/' #endif path.reserve(path.size() + element.size() + 2); int added_separator = 0; @@ -389,8 +389,7 @@ namespace { std::time_t const mtime = std::time_t(dict.dict_find_int_value("mtime", 0)); std::string path = root_dir; - char const* filename = nullptr; - int filename_len = 0; + string_view filename; if (top_level) { @@ -404,8 +403,12 @@ namespace { return false; } - filename = p.string_ptr() + info_ptr_diff; - filename_len = p.string_length(); + filename = { p.string_ptr() + info_ptr_diff + , static_cast(p.string_length())}; + + while (!filename.empty() && filename.front() == TORRENT_SEPARATOR) + filename.remove_prefix(1); + sanitize_append_path_element(path, p.string_value()); if (path.empty()) { @@ -429,8 +432,10 @@ namespace { bdecode_node const e = p.list_at(i); if (i == end - 1) { - filename = e.string_ptr() + info_ptr_diff; - filename_len = e.string_length(); + filename = {e.string_ptr() + info_ptr_diff + , static_cast(e.string_length()) }; + while (!filename.empty() && filename.front() == TORRENT_SEPARATOR) + filename.remove_prefix(1); } sanitize_append_path_element(path, e.string_value()); } @@ -480,16 +485,14 @@ namespace { file_flags &= ~file_storage::flag_symlink; } - if (filename_len > int(path.length()) - || path.compare(path.size() - std::size_t(filename_len), std::size_t(filename_len), filename - , std::size_t(filename_len)) != 0) + if (filename.size() > path.length() + || path.substr(path.size() - filename.size()) != filename) { // if the filename was sanitized and differ, clear it to just use path - filename = nullptr; - filename_len = 0; + filename = {}; } - files.add_file_borrow({filename, std::size_t(filename_len)}, path, file_size, file_flags, filehash + files.add_file_borrow(filename, path, file_size, file_flags, filehash , mtime, symlink_path); return true; } @@ -644,7 +647,7 @@ namespace { { p = parent_path(p); // we don't want trailing slashes here - TORRENT_ASSERT(p[p.size() - 1] == *TORRENT_SEPARATOR); + TORRENT_ASSERT(p[p.size() - 1] == TORRENT_SEPARATOR); p.resize(p.size() - 1); files.insert(p); } diff --git a/test/test_torrent_info.cpp b/test/test_torrent_info.cpp index 6e15bd091..a239d8756 100644 --- a/test/test_torrent_info.cpp +++ b/test/test_torrent_info.cpp @@ -127,6 +127,7 @@ static test_torrent_t test_torrents[] = { "symlink_zero_size.torrent" }, { "pad_file_no_path.torrent" }, { "large.torrent" }, + { "absolute_filename.torrent" }, }; struct test_failing_torrent_t @@ -795,6 +796,12 @@ TORRENT_TEST(parse_torrents) TEST_EQUAL(ti->num_files(), 2); TEST_EQUAL(ti->files().file_path(file_index_t{1}), combine_path(".pad", "0")); } + else if (std::string(test_torrents[i].file) == "absolute_filename.torrent") + { + TEST_EQUAL(ti->num_files(), 2); + TEST_EQUAL(ti->files().file_path(file_index_t{0}), combine_path("temp", "abcde")); + TEST_EQUAL(ti->files().file_path(file_index_t{1}), combine_path("temp", "foobar")); + } file_storage const& fs = ti->files(); for (file_index_t i{0}; i != file_index_t(fs.num_files()); ++i) diff --git a/test/test_torrents/absolute_filename.torrent b/test/test_torrents/absolute_filename.torrent new file mode 100644 index 000000000..b5c8a7c76 --- /dev/null +++ b/test/test_torrents/absolute_filename.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld6:lengthi425e4:pathl5:abcdeeed6:lengthi5e4:pathl7:/foobareee4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee