diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h index b632654d..f40f4c06 100644 --- a/src/google_breakpad/processor/minidump.h +++ b/src/google_breakpad/processor/minidump.h @@ -221,6 +221,9 @@ class MinidumpMemoryRegion : public MinidumpObject, public: virtual ~MinidumpMemoryRegion(); + static void set_max_bytes(u_int32_t max_bytes) { max_bytes_ = max_bytes; } + static u_int32_t max_bytes() { return max_bytes_; } + // Returns a pointer to the base of the memory region. Returns the // cached value if available, otherwise, reads the minidump file and // caches the memory region. @@ -258,6 +261,10 @@ class MinidumpMemoryRegion : public MinidumpObject, template bool GetMemoryAtAddressInternal(u_int64_t address, T* value); + // The largest memory region that will be read from a minidump. The + // default is 1MB. + static u_int32_t max_bytes_; + // Base address and size of the memory region, and its position in the // minidump file. MDMemoryDescriptor* descriptor_; @@ -312,6 +319,11 @@ class MinidumpThreadList : public MinidumpStream { public: virtual ~MinidumpThreadList(); + static void set_max_threads(u_int32_t max_threads) { + max_threads_ = max_threads; + } + static u_int32_t max_threads() { return max_threads_; } + unsigned int thread_count() const { return valid_ ? thread_count_ : 0; } // Sequential access to threads. @@ -335,6 +347,10 @@ class MinidumpThreadList : public MinidumpStream { bool Read(u_int32_t aExpectedSize); + // The largest number of threads that will be read from a minidump. The + // default is 256. + static u_int32_t max_threads_; + // Access to threads using the thread ID as the key. IDToThreadMap id_to_thread_map_; @@ -353,6 +369,16 @@ class MinidumpModule : public MinidumpObject, public: virtual ~MinidumpModule(); + static void set_max_cv_bytes(u_int32_t max_cv_bytes) { + max_cv_bytes_ = max_cv_bytes; + } + static u_int32_t max_cv_bytes() { return max_cv_bytes_; } + + static void set_max_misc_bytes(u_int32_t max_misc_bytes) { + max_misc_bytes_ = max_misc_bytes; + } + static u_int32_t max_misc_bytes() { return max_misc_bytes_; } + const MDRawModule* module() const { return valid_ ? &module_ : NULL; } // CodeModule implementation @@ -408,6 +434,12 @@ class MinidumpModule : public MinidumpObject, // allow the CodeModule getters to be const methods. bool ReadAuxiliaryData(); + // The largest number of bytes that will be read from a minidump for a + // CodeView record or miscellaneous debugging record, respectively. The + // default for each is 1024. + static u_int32_t max_cv_bytes_; + static u_int32_t max_misc_bytes_; + // True after a successful Read. This is different from valid_, which is // not set true until ReadAuxiliaryData also completes successfully. // module_valid_ is only used by ReadAuxiliaryData and the functions it @@ -447,6 +479,11 @@ class MinidumpModuleList : public MinidumpStream, public: virtual ~MinidumpModuleList(); + static void set_max_modules(u_int32_t max_modules) { + max_modules_ = max_modules; + } + static u_int32_t max_modules() { return max_modules_; } + // CodeModules implementation. virtual unsigned int module_count() const { return valid_ ? module_count_ : 0; @@ -472,6 +509,10 @@ class MinidumpModuleList : public MinidumpStream, bool Read(u_int32_t expected_size); + // The largest number of modules that will be read from a minidump. The + // default is 1024. + static u_int32_t max_modules_; + // Access to modules using addresses as the key. RangeMap *range_map_; @@ -493,6 +534,11 @@ class MinidumpMemoryList : public MinidumpStream { public: virtual ~MinidumpMemoryList(); + static void set_max_regions(u_int32_t max_regions) { + max_regions_ = max_regions; + } + static u_int32_t max_regions() { return max_regions_; } + unsigned int region_count() const { return valid_ ? region_count_ : 0; } // Sequential access to memory regions. @@ -517,6 +563,10 @@ class MinidumpMemoryList : public MinidumpStream { bool Read(u_int32_t expected_size); + // The largest number of memory regions that will be read from a minidump. + // The default is 256. + static u_int32_t max_regions_; + // Access to memory regions using addresses as the key. RangeMap *range_map_; @@ -690,6 +740,16 @@ class Minidump { ~Minidump(); + static void set_max_streams(u_int32_t max_streams) { + max_streams_ = max_streams; + } + static u_int32_t max_streams() { return max_streams_; } + + static void set_max_string_length(u_int32_t max_string_length) { + max_string_length_ = max_string_length; + } + static u_int32_t max_string_length() { return max_string_length_; } + const MDRawHeader* header() const { return valid_ ? &header_ : NULL; } // Reads the minidump file's header and top-level stream directory. @@ -779,6 +839,17 @@ class Minidump { // Opens the minidump file, or if already open, seeks to the beginning. bool Open(); + // The largest number of top-level streams that will be read from a minidump. + // Note that streams are only read (and only consume memory) as needed, + // when directed by the caller. The default is 128. + static u_int32_t max_streams_; + + // The maximum length of a UTF-16 string that will be read from a minidump + // in 16-bit words. The default is 1024. UTF-16 strings are converted + // to UTF-8 when stored in memory, and each UTF-16 word will be represented + // by as many as 3 bytes in UTF-8. + static unsigned int max_string_length_; + MDRawHeader header_; // The list of streams. diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index e1828a6b..ed0ba365 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -686,6 +686,9 @@ void MinidumpContext::Print() { // +u_int32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024; // 1MB + + MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump) : MinidumpObject(minidump), descriptor_(NULL), @@ -724,7 +727,13 @@ const u_int8_t* MinidumpMemoryRegion::GetMemory() { return NULL; } - // TODO(mmentovai): verify rational size! + if (descriptor_->memory.data_size > max_bytes_) { + BPLOG(ERROR) << "MinidumpMemoryRegion size " << + descriptor_->memory.data_size << " exceeds maximum " << + max_bytes_; + return NULL; + } + scoped_ptr< vector > memory( new vector(descriptor_->memory.data_size)); @@ -1014,6 +1023,9 @@ void MinidumpThread::Print() { // +u_int32_t MinidumpThreadList::max_threads_ = 256; + + MinidumpThreadList::MinidumpThreadList(Minidump* minidump) : MinidumpStream(minidump), id_to_thread_map_(), @@ -1064,8 +1076,13 @@ bool MinidumpThreadList::Read(u_int32_t expected_size) { return false; } - if (thread_count) { - // TODO(mmentovai): verify rational size! + if (thread_count > max_threads_) { + BPLOG(ERROR) << "MinidumpThreadList count " << thread_count << + " exceeds maximum " << max_threads_; + return false; + } + + if (thread_count != 0) { scoped_ptr threads( new MinidumpThreads(thread_count, MinidumpThread(minidump_))); @@ -1157,6 +1174,10 @@ void MinidumpThreadList::Print() { // +u_int32_t MinidumpModule::max_cv_bytes_ = 1024; +u_int32_t MinidumpModule::max_misc_bytes_ = 1024; + + MinidumpModule::MinidumpModule(Minidump* minidump) : MinidumpObject(minidump), module_valid_(false), @@ -1526,7 +1547,12 @@ const u_int8_t* MinidumpModule::GetCVRecord(u_int32_t* size) { return NULL; } - // TODO(mmentovai): verify rational size! + if (module_.cv_record.data_size > max_cv_bytes_) { + BPLOG(ERROR) << "MinidumpModule CodeView record size " << + module_.cv_record.data_size << " exceeds maximum " << + max_cv_bytes_; + return NULL; + } // Allocating something that will be accessed as MDCVInfoPDB70 or // MDCVInfoPDB20 but is allocated as u_int8_t[] can cause alignment @@ -1649,7 +1675,12 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord(u_int32_t* size) { return NULL; } - // TODO(mmentovai): verify rational size! + if (module_.misc_record.data_size > max_misc_bytes_) { + BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " << + module_.misc_record.data_size << " exceeds maximum " << + max_misc_bytes_; + return NULL; + } // Allocating something that will be accessed as MDImageDebugMisc but // is allocated as u_int8_t[] can cause alignment problems. x86 and @@ -1847,6 +1878,9 @@ void MinidumpModule::Print() { // +u_int32_t MinidumpModuleList::max_modules_ = 1024; + + MinidumpModuleList::MinidumpModuleList(Minidump* minidump) : MinidumpStream(minidump), range_map_(new RangeMap()), @@ -1898,8 +1932,13 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) { return false; } - if (module_count) { - // TODO(mmentovai): verify rational size! + if (module_count > max_modules_) { + BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ << + " exceeds maximum " << max_modules_; + return false; + } + + if (module_count != 0) { scoped_ptr modules( new MinidumpModules(module_count, MinidumpModule(minidump_))); @@ -2065,6 +2104,9 @@ void MinidumpModuleList::Print() { // +u_int32_t MinidumpMemoryList::max_regions_ = 256; + + MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump) : MinidumpStream(minidump), range_map_(new RangeMap()), @@ -2120,8 +2162,13 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) { return false; } - if (region_count) { - // TODO(mmentovai): verify rational size! + if (region_count > max_regions_) { + BPLOG(ERROR) << "MinidumpMemoryList count " << region_count << + " exceeds maximum " << max_regions_; + return false; + } + + if (region_count != 0) { scoped_ptr descriptors( new MemoryDescriptors(region_count)); @@ -2821,6 +2868,10 @@ void MinidumpBreakpadInfo::Print() { // +u_int32_t Minidump::max_streams_ = 128; +unsigned int Minidump::max_string_length_ = 1024; + + Minidump::Minidump(const string& path) : header_(), directory_(NULL), @@ -2934,8 +2985,13 @@ bool Minidump::Read() { return false; } - if (header_.stream_count) { - // TODO(mmentovai): verify rational size! + if (header_.stream_count > max_streams_) { + BPLOG(ERROR) << "Minidump stream count " << header_.stream_count << + " exceeds maximum " << max_streams_; + return false; + } + + if (header_.stream_count != 0) { scoped_ptr directory( new MinidumpDirectoryEntries(header_.stream_count)); @@ -3146,31 +3202,39 @@ string* Minidump::ReadString(off_t offset) { return NULL; } if (!SeekSet(offset)) { - BPLOG(ERROR) << "ReadString could not seek to string"; + BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset; return NULL; } u_int32_t bytes; if (!ReadBytes(&bytes, sizeof(bytes))) { - BPLOG(ERROR) << "ReadString could not read string size"; + BPLOG(ERROR) << "ReadString could not read string size at offset " << + offset; return NULL; } if (swap_) Swap(&bytes); if (bytes % 2 != 0) { - BPLOG(ERROR) << "ReadString found odd-sized string of " << bytes << - " bytes at offset " << offset; + BPLOG(ERROR) << "ReadString found odd-sized " << bytes << + "-byte string at offset " << offset; return NULL; } unsigned int utf16_words = bytes / 2; - // TODO(mmentovai): verify rational size! + if (utf16_words > max_string_length_) { + BPLOG(ERROR) << "ReadString string length " << utf16_words << + " exceeds maximum " << max_string_length_ << + " at offset " << offset; + return NULL; + } + vector string_utf16(utf16_words); if (utf16_words) { if (!ReadBytes(&string_utf16[0], bytes)) { - BPLOG(ERROR) << "ReadString could not read string"; + BPLOG(ERROR) << "ReadString could not read " << bytes << + "-byte string at offset " << offset; return NULL; } }