From aecbcf3aaf506f46e45fafcf594cb1c4e8ea9eff Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sun, 20 Sep 2026 19:01:33 +0200 Subject: [PATCH] Clamp the marCCD header probe to the size of the file The header offset comes from TIFF tag 34710 unchecked and is handed to ReadPrefix, which allocates that many bytes before reading. This runs during format autodetection, on files nobody has said are marCCD, so a foreign or corrupt TIFF could have the program allocate ~4 GB for a probe. The probe now reads at most what the file holds; a short read was always the normal outcome and the caller already checks the size. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT --- reader/MarCCD.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/reader/MarCCD.cpp b/reader/MarCCD.cpp index a5ee68d3a..96af47893 100644 --- a/reader/MarCCD.cpp +++ b/reader/MarCCD.cpp @@ -60,6 +60,15 @@ std::vector ReadPrefix(const std::string &path, size_t bytes) { std::ifstream f(path, std::ios::binary); if (!f) throw JFJochException(JFJochExceptionCategory::MockFileOpenError, "Cannot open " + path); + // Never allocate more than the file holds. One caller's count comes from the header-offset TIFF + // tag, which is a field of a file nobody has yet decided is ours - this runs on every input the + // program is given - and a foreign or corrupt TIFF can name four gigabytes there. Reading short + // is already the normal outcome (the caller checks the size it got back), so the clamp costs + // nothing. + f.seekg(0, std::ios::end); + const std::streamoff file_bytes = f.tellg(); + f.seekg(0, std::ios::beg); + bytes = std::min(bytes, file_bytes > 0 ? static_cast(file_bytes) : size_t(0)); std::vector out(bytes); f.read(reinterpret_cast(out.data()), static_cast(bytes)); out.resize(static_cast(f.gcount()));