From e6b0a84f3ad92b3c182e5cd32893d96273493ad6 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 09:36:54 -0700 Subject: [PATCH] fix(wcp): cap pack file count at unpack limit (1M) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pack previously trusted recursive_directory_iterator to terminate naturally — fine on most zones but a hostile symlink loop or a giant accidental subdirectory would produce an archive with > 1M files, which the unpack header check rejects wholesale. Cap at the unpack limit and log a warning so the resulting WCP is at least loadable, even if incomplete. --- tools/editor/content_pack.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/editor/content_pack.cpp b/tools/editor/content_pack.cpp index 9946a51b..c4d30ce6 100644 --- a/tools/editor/content_pack.cpp +++ b/tools/editor/content_pack.cpp @@ -31,9 +31,19 @@ bool ContentPacker::packZone(const std::string& outputDir, const std::string& ma // on Windows are readable on Linux/macOS and vice versa — the unpack // path-traversal check rejects '\' as an absolute prefix, so a Windows // path leaks would silently fail to extract. + // + // Cap total file count at the unpack-side limit (1M) so a runaway + // recursive_directory_iterator on a hostile symlink loop or a giant + // accidental subdirectory doesn't produce an unpackable archive. + constexpr size_t kMaxFiles = 1'000'000; std::vector> files; // relative path, full path for (auto& entry : fs::recursive_directory_iterator(srcDir)) { if (!entry.is_regular_file()) continue; + if (files.size() >= kMaxFiles) { + LOG_WARNING("WCP file count cap reached (", kMaxFiles, + "); remaining files in ", srcDir, " omitted"); + break; + } std::string rel = fs::relative(entry.path(), srcDir).string(); std::replace(rel.begin(), rel.end(), '\\', '/'); files.push_back({rel, entry.path().string()});