mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-01-24 10:11:04 +00:00
Check allocation and array sizes in minidump.cc (#12). r=bryner
http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/7258b34d26ffc890 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@182 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
46b60801cb
commit
e96a791d9a
|
@ -221,6 +221,9 @@ class MinidumpMemoryRegion : public MinidumpObject,
|
||||||
public:
|
public:
|
||||||
virtual ~MinidumpMemoryRegion();
|
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
|
// Returns a pointer to the base of the memory region. Returns the
|
||||||
// cached value if available, otherwise, reads the minidump file and
|
// cached value if available, otherwise, reads the minidump file and
|
||||||
// caches the memory region.
|
// caches the memory region.
|
||||||
|
@ -258,6 +261,10 @@ class MinidumpMemoryRegion : public MinidumpObject,
|
||||||
template<typename T> bool GetMemoryAtAddressInternal(u_int64_t address,
|
template<typename T> bool GetMemoryAtAddressInternal(u_int64_t address,
|
||||||
T* value);
|
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
|
// Base address and size of the memory region, and its position in the
|
||||||
// minidump file.
|
// minidump file.
|
||||||
MDMemoryDescriptor* descriptor_;
|
MDMemoryDescriptor* descriptor_;
|
||||||
|
@ -312,6 +319,11 @@ class MinidumpThreadList : public MinidumpStream {
|
||||||
public:
|
public:
|
||||||
virtual ~MinidumpThreadList();
|
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; }
|
unsigned int thread_count() const { return valid_ ? thread_count_ : 0; }
|
||||||
|
|
||||||
// Sequential access to threads.
|
// Sequential access to threads.
|
||||||
|
@ -335,6 +347,10 @@ class MinidumpThreadList : public MinidumpStream {
|
||||||
|
|
||||||
bool Read(u_int32_t aExpectedSize);
|
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.
|
// Access to threads using the thread ID as the key.
|
||||||
IDToThreadMap id_to_thread_map_;
|
IDToThreadMap id_to_thread_map_;
|
||||||
|
|
||||||
|
@ -353,6 +369,16 @@ class MinidumpModule : public MinidumpObject,
|
||||||
public:
|
public:
|
||||||
virtual ~MinidumpModule();
|
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; }
|
const MDRawModule* module() const { return valid_ ? &module_ : NULL; }
|
||||||
|
|
||||||
// CodeModule implementation
|
// CodeModule implementation
|
||||||
|
@ -408,6 +434,12 @@ class MinidumpModule : public MinidumpObject,
|
||||||
// allow the CodeModule getters to be const methods.
|
// allow the CodeModule getters to be const methods.
|
||||||
bool ReadAuxiliaryData();
|
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
|
// True after a successful Read. This is different from valid_, which is
|
||||||
// not set true until ReadAuxiliaryData also completes successfully.
|
// not set true until ReadAuxiliaryData also completes successfully.
|
||||||
// module_valid_ is only used by ReadAuxiliaryData and the functions it
|
// module_valid_ is only used by ReadAuxiliaryData and the functions it
|
||||||
|
@ -447,6 +479,11 @@ class MinidumpModuleList : public MinidumpStream,
|
||||||
public:
|
public:
|
||||||
virtual ~MinidumpModuleList();
|
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.
|
// CodeModules implementation.
|
||||||
virtual unsigned int module_count() const {
|
virtual unsigned int module_count() const {
|
||||||
return valid_ ? module_count_ : 0;
|
return valid_ ? module_count_ : 0;
|
||||||
|
@ -472,6 +509,10 @@ class MinidumpModuleList : public MinidumpStream,
|
||||||
|
|
||||||
bool Read(u_int32_t expected_size);
|
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.
|
// Access to modules using addresses as the key.
|
||||||
RangeMap<u_int64_t, unsigned int> *range_map_;
|
RangeMap<u_int64_t, unsigned int> *range_map_;
|
||||||
|
|
||||||
|
@ -493,6 +534,11 @@ class MinidumpMemoryList : public MinidumpStream {
|
||||||
public:
|
public:
|
||||||
virtual ~MinidumpMemoryList();
|
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; }
|
unsigned int region_count() const { return valid_ ? region_count_ : 0; }
|
||||||
|
|
||||||
// Sequential access to memory regions.
|
// Sequential access to memory regions.
|
||||||
|
@ -517,6 +563,10 @@ class MinidumpMemoryList : public MinidumpStream {
|
||||||
|
|
||||||
bool Read(u_int32_t expected_size);
|
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.
|
// Access to memory regions using addresses as the key.
|
||||||
RangeMap<u_int64_t, unsigned int> *range_map_;
|
RangeMap<u_int64_t, unsigned int> *range_map_;
|
||||||
|
|
||||||
|
@ -690,6 +740,16 @@ class Minidump {
|
||||||
|
|
||||||
~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; }
|
const MDRawHeader* header() const { return valid_ ? &header_ : NULL; }
|
||||||
|
|
||||||
// Reads the minidump file's header and top-level stream directory.
|
// 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.
|
// Opens the minidump file, or if already open, seeks to the beginning.
|
||||||
bool Open();
|
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_;
|
MDRawHeader header_;
|
||||||
|
|
||||||
// The list of streams.
|
// The list of streams.
|
||||||
|
|
|
@ -686,6 +686,9 @@ void MinidumpContext::Print() {
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
u_int32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024; // 1MB
|
||||||
|
|
||||||
|
|
||||||
MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
|
MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
|
||||||
: MinidumpObject(minidump),
|
: MinidumpObject(minidump),
|
||||||
descriptor_(NULL),
|
descriptor_(NULL),
|
||||||
|
@ -724,7 +727,13 @@ const u_int8_t* MinidumpMemoryRegion::GetMemory() {
|
||||||
return NULL;
|
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<u_int8_t> > memory(
|
scoped_ptr< vector<u_int8_t> > memory(
|
||||||
new vector<u_int8_t>(descriptor_->memory.data_size));
|
new vector<u_int8_t>(descriptor_->memory.data_size));
|
||||||
|
|
||||||
|
@ -1014,6 +1023,9 @@ void MinidumpThread::Print() {
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
u_int32_t MinidumpThreadList::max_threads_ = 256;
|
||||||
|
|
||||||
|
|
||||||
MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
|
MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
|
||||||
: MinidumpStream(minidump),
|
: MinidumpStream(minidump),
|
||||||
id_to_thread_map_(),
|
id_to_thread_map_(),
|
||||||
|
@ -1064,8 +1076,13 @@ bool MinidumpThreadList::Read(u_int32_t expected_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thread_count) {
|
if (thread_count > max_threads_) {
|
||||||
// TODO(mmentovai): verify rational size!
|
BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
|
||||||
|
" exceeds maximum " << max_threads_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread_count != 0) {
|
||||||
scoped_ptr<MinidumpThreads> threads(
|
scoped_ptr<MinidumpThreads> threads(
|
||||||
new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
|
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)
|
MinidumpModule::MinidumpModule(Minidump* minidump)
|
||||||
: MinidumpObject(minidump),
|
: MinidumpObject(minidump),
|
||||||
module_valid_(false),
|
module_valid_(false),
|
||||||
|
@ -1526,7 +1547,12 @@ const u_int8_t* MinidumpModule::GetCVRecord(u_int32_t* size) {
|
||||||
return NULL;
|
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
|
// Allocating something that will be accessed as MDCVInfoPDB70 or
|
||||||
// MDCVInfoPDB20 but is allocated as u_int8_t[] can cause alignment
|
// 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;
|
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
|
// Allocating something that will be accessed as MDImageDebugMisc but
|
||||||
// is allocated as u_int8_t[] can cause alignment problems. x86 and
|
// 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)
|
MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
|
||||||
: MinidumpStream(minidump),
|
: MinidumpStream(minidump),
|
||||||
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
||||||
|
@ -1898,8 +1932,13 @@ bool MinidumpModuleList::Read(u_int32_t expected_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module_count) {
|
if (module_count > max_modules_) {
|
||||||
// TODO(mmentovai): verify rational size!
|
BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ <<
|
||||||
|
" exceeds maximum " << max_modules_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module_count != 0) {
|
||||||
scoped_ptr<MinidumpModules> modules(
|
scoped_ptr<MinidumpModules> modules(
|
||||||
new MinidumpModules(module_count, MinidumpModule(minidump_)));
|
new MinidumpModules(module_count, MinidumpModule(minidump_)));
|
||||||
|
|
||||||
|
@ -2065,6 +2104,9 @@ void MinidumpModuleList::Print() {
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
u_int32_t MinidumpMemoryList::max_regions_ = 256;
|
||||||
|
|
||||||
|
|
||||||
MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
|
MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
|
||||||
: MinidumpStream(minidump),
|
: MinidumpStream(minidump),
|
||||||
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
range_map_(new RangeMap<u_int64_t, unsigned int>()),
|
||||||
|
@ -2120,8 +2162,13 @@ bool MinidumpMemoryList::Read(u_int32_t expected_size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region_count) {
|
if (region_count > max_regions_) {
|
||||||
// TODO(mmentovai): verify rational size!
|
BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
|
||||||
|
" exceeds maximum " << max_regions_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region_count != 0) {
|
||||||
scoped_ptr<MemoryDescriptors> descriptors(
|
scoped_ptr<MemoryDescriptors> descriptors(
|
||||||
new MemoryDescriptors(region_count));
|
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)
|
Minidump::Minidump(const string& path)
|
||||||
: header_(),
|
: header_(),
|
||||||
directory_(NULL),
|
directory_(NULL),
|
||||||
|
@ -2934,8 +2985,13 @@ bool Minidump::Read() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header_.stream_count) {
|
if (header_.stream_count > max_streams_) {
|
||||||
// TODO(mmentovai): verify rational size!
|
BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
|
||||||
|
" exceeds maximum " << max_streams_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_.stream_count != 0) {
|
||||||
scoped_ptr<MinidumpDirectoryEntries> directory(
|
scoped_ptr<MinidumpDirectoryEntries> directory(
|
||||||
new MinidumpDirectoryEntries(header_.stream_count));
|
new MinidumpDirectoryEntries(header_.stream_count));
|
||||||
|
|
||||||
|
@ -3146,31 +3202,39 @@ string* Minidump::ReadString(off_t offset) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!SeekSet(offset)) {
|
if (!SeekSet(offset)) {
|
||||||
BPLOG(ERROR) << "ReadString could not seek to string";
|
BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u_int32_t bytes;
|
u_int32_t bytes;
|
||||||
if (!ReadBytes(&bytes, sizeof(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;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (swap_)
|
if (swap_)
|
||||||
Swap(&bytes);
|
Swap(&bytes);
|
||||||
|
|
||||||
if (bytes % 2 != 0) {
|
if (bytes % 2 != 0) {
|
||||||
BPLOG(ERROR) << "ReadString found odd-sized string of " << bytes <<
|
BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
|
||||||
" bytes at offset " << offset;
|
"-byte string at offset " << offset;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
unsigned int utf16_words = bytes / 2;
|
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<u_int16_t> string_utf16(utf16_words);
|
vector<u_int16_t> string_utf16(utf16_words);
|
||||||
|
|
||||||
if (utf16_words) {
|
if (utf16_words) {
|
||||||
if (!ReadBytes(&string_utf16[0], bytes)) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue