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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT
This commit is contained in:
2026-09-20 19:01:33 +02:00
co-authored by Claude Opus 5
parent 404b233aa8
commit aecbcf3aaf
+9
View File
@@ -60,6 +60,15 @@ std::vector<uint8_t> 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<size_t>(file_bytes) : size_t(0));
std::vector<uint8_t> out(bytes);
f.read(reinterpret_cast<char *>(out.data()), static_cast<std::streamsize>(bytes));
out.resize(static_cast<size_t>(f.gcount()));