Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 #include "snapshot/win/pe_image_reader.h" | 15 #include "snapshot/win/pe_image_reader.h" |
| 16 | 16 |
| 17 #include <string.h> | 17 #include <string.h> |
| 18 | 18 |
| 19 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "base/memory/scoped_ptr.h" | 20 #include "base/memory/scoped_ptr.h" |
| 21 #include "base/strings/stringprintf.h" | |
| 22 #include "client/crashpad_info.h" | 21 #include "client/crashpad_info.h" |
| 22 #include "snapshot/win/pe_image_resource_reader.h" | |
| 23 #include "snapshot/win/process_reader_win.h" | 23 #include "snapshot/win/process_reader_win.h" |
| 24 #include "util/misc/pdb_structures.h" | 24 #include "util/misc/pdb_structures.h" |
| 25 #include "util/win/process_structs.h" | 25 #include "util/win/process_structs.h" |
| 26 | 26 |
| 27 namespace crashpad { | 27 namespace crashpad { |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 | 30 |
| 31 std::string RangeToString(const CheckedWinAddressRange& range) { | |
| 32 return base::StringPrintf("[0x%llx + 0x%llx (%s)]", | |
| 33 range.Base(), | |
| 34 range.Size(), | |
| 35 range.Is64Bit() ? "64" : "32"); | |
| 36 } | |
| 37 | |
| 38 // Map from Traits to an IMAGE_NT_HEADERSxx. | 31 // Map from Traits to an IMAGE_NT_HEADERSxx. |
| 39 template <class Traits> | 32 template <class Traits> |
| 40 struct NtHeadersForTraits; | 33 struct NtHeadersForTraits; |
| 41 | 34 |
| 42 template <> | 35 template <> |
| 43 struct NtHeadersForTraits<process_types::internal::Traits32> { | 36 struct NtHeadersForTraits<process_types::internal::Traits32> { |
| 44 using type = IMAGE_NT_HEADERS32; | 37 using type = IMAGE_NT_HEADERS32; |
| 45 }; | 38 }; |
| 46 | 39 |
| 47 template <> | 40 template <> |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 64 bool PEImageReader::Initialize(ProcessReaderWin* process_reader, | 57 bool PEImageReader::Initialize(ProcessReaderWin* process_reader, |
| 65 WinVMAddress address, | 58 WinVMAddress address, |
| 66 WinVMSize size, | 59 WinVMSize size, |
| 67 const std::string& module_name) { | 60 const std::string& module_name) { |
| 68 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 61 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| 69 | 62 |
| 70 process_reader_ = process_reader; | 63 process_reader_ = process_reader; |
| 71 module_range_.SetRange(process_reader_->Is64Bit(), address, size); | 64 module_range_.SetRange(process_reader_->Is64Bit(), address, size); |
| 72 if (!module_range_.IsValid()) { | 65 if (!module_range_.IsValid()) { |
| 73 LOG(WARNING) << "invalid module range for " << module_name << ": " | 66 LOG(WARNING) << "invalid module range for " << module_name << ": " |
| 74 << RangeToString(module_range_); | 67 << module_range_.AsString(); |
| 75 return false; | 68 return false; |
| 76 } | 69 } |
| 77 module_name_ = module_name; | 70 module_name_ = module_name; |
| 78 | 71 |
| 79 INITIALIZATION_STATE_SET_VALID(initialized_); | 72 INITIALIZATION_STATE_SET_VALID(initialized_); |
| 80 return true; | 73 return true; |
| 81 } | 74 } |
| 82 | 75 |
| 83 template <class Traits> | 76 template <class Traits> |
| 84 bool PEImageReader::GetCrashpadInfo( | 77 bool PEImageReader::GetCrashpadInfo( |
| 85 process_types::CrashpadInfo<Traits>* crashpad_info) const { | 78 process_types::CrashpadInfo<Traits>* crashpad_info) const { |
| 86 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 79 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 87 | 80 |
| 88 IMAGE_SECTION_HEADER section; | 81 IMAGE_SECTION_HEADER section; |
| 89 if (!GetSectionByName<NtHeadersForTraits<Traits>::type>("CPADinfo", §ion)) | 82 if (!GetSectionByName<NtHeadersForTraits<Traits>::type>("CPADinfo", §ion)) |
| 90 return false; | 83 return false; |
| 91 | 84 |
| 92 if (section.Misc.VirtualSize < sizeof(process_types::CrashpadInfo<Traits>)) { | 85 if (section.Misc.VirtualSize < sizeof(process_types::CrashpadInfo<Traits>)) { |
| 93 LOG(WARNING) << "small crashpad info section size " | 86 LOG(WARNING) << "small crashpad info section size " |
| 94 << section.Misc.VirtualSize << ", " << module_name_; | 87 << section.Misc.VirtualSize << ", " << module_name_; |
| 95 return false; | 88 return false; |
| 96 } | 89 } |
| 97 | 90 |
| 98 WinVMAddress crashpad_info_address = Address() + section.VirtualAddress; | 91 WinVMAddress crashpad_info_address = Address() + section.VirtualAddress; |
| 99 CheckedWinAddressRange crashpad_info_range(process_reader_->Is64Bit(), | 92 CheckedWinAddressRange crashpad_info_range(process_reader_->Is64Bit(), |
| 100 crashpad_info_address, | 93 crashpad_info_address, |
| 101 section.Misc.VirtualSize); | 94 section.Misc.VirtualSize); |
| 102 if (!crashpad_info_range.IsValid()) { | 95 if (!crashpad_info_range.IsValid()) { |
| 103 LOG(WARNING) << "invalid range for crashpad info: " | 96 LOG(WARNING) << "invalid range for crashpad info: " |
| 104 << RangeToString(crashpad_info_range); | 97 << crashpad_info_range.AsString(); |
| 105 return false; | 98 return false; |
| 106 } | 99 } |
| 107 | 100 |
| 108 if (!module_range_.ContainsRange(crashpad_info_range)) { | 101 if (!module_range_.ContainsRange(crashpad_info_range)) { |
| 109 LOG(WARNING) << "crashpad info does not fall inside module " | 102 LOG(WARNING) << "crashpad info does not fall inside module " |
| 110 << module_name_; | 103 << module_name_; |
| 111 return false; | 104 return false; |
| 112 } | 105 } |
| 113 | 106 |
| 114 if (!process_reader_->ReadMemory(crashpad_info_address, | 107 if (!process_reader_->ReadMemory(crashpad_info_address, |
| 115 sizeof(process_types::CrashpadInfo<Traits>), | 108 sizeof(process_types::CrashpadInfo<Traits>), |
| 116 crashpad_info)) { | 109 crashpad_info)) { |
| 117 LOG(WARNING) << "could not read crashpad info " << module_name_; | 110 LOG(WARNING) << "could not read crashpad info " << module_name_; |
| 118 return false; | 111 return false; |
| 119 } | 112 } |
| 120 | 113 |
| 121 if (crashpad_info->signature != CrashpadInfo::kSignature || | 114 if (crashpad_info->signature != CrashpadInfo::kSignature || |
| 122 crashpad_info->version < 1) { | 115 crashpad_info->version < 1) { |
| 123 LOG(WARNING) << "unexpected crashpad info data " << module_name_; | 116 LOG(WARNING) << "unexpected crashpad info data " << module_name_; |
| 124 return false; | 117 return false; |
| 125 } | 118 } |
| 126 | 119 |
| 127 return true; | 120 return true; |
| 128 } | 121 } |
| 129 | 122 |
| 130 bool PEImageReader::DebugDirectoryInformation(UUID* uuid, | 123 bool PEImageReader::DebugDirectoryInformation(UUID* uuid, |
| 131 DWORD* age, | 124 DWORD* age, |
| 132 std::string* pdbname) const { | 125 std::string* pdbname) const { |
| 133 if (process_reader_->Is64Bit()) { | 126 IMAGE_DATA_DIRECTORY data_directory; |
| 134 return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS64>( | 127 if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG, &data_directory)) |
| 135 uuid, age, pdbname); | |
| 136 } else { | |
| 137 return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS32>( | |
| 138 uuid, age, pdbname); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 template <class NtHeadersType> | |
| 143 bool PEImageReader::ReadDebugDirectoryInformation(UUID* uuid, | |
| 144 DWORD* age, | |
| 145 std::string* pdbname) const { | |
| 146 NtHeadersType nt_headers; | |
| 147 if (!ReadNtHeaders(&nt_headers, nullptr)) | |
| 148 return false; | 128 return false; |
| 149 | 129 |
| 150 if (nt_headers.FileHeader.SizeOfOptionalHeader < | |
| 151 offsetof(decltype(nt_headers.OptionalHeader), | |
| 152 DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) + | |
| 153 sizeof(nt_headers.OptionalHeader | |
| 154 .DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) || | |
| 155 nt_headers.OptionalHeader.NumberOfRvaAndSizes <= | |
| 156 IMAGE_DIRECTORY_ENTRY_DEBUG) { | |
| 157 return false; | |
| 158 } | |
| 159 | |
| 160 const IMAGE_DATA_DIRECTORY& data_directory = | |
| 161 nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]; | |
| 162 if (data_directory.VirtualAddress == 0 || data_directory.Size == 0) | |
| 163 return false; | |
| 164 IMAGE_DEBUG_DIRECTORY debug_directory; | 130 IMAGE_DEBUG_DIRECTORY debug_directory; |
| 165 if (data_directory.Size % sizeof(debug_directory) != 0) | 131 if (data_directory.Size % sizeof(debug_directory) != 0) |
| 166 return false; | 132 return false; |
| 167 for (size_t offset = 0; offset < data_directory.Size; | 133 for (size_t offset = 0; offset < data_directory.Size; |
| 168 offset += sizeof(debug_directory)) { | 134 offset += sizeof(debug_directory)) { |
| 169 if (!CheckedReadMemory(Address() + data_directory.VirtualAddress + offset, | 135 if (!CheckedReadMemory(Address() + data_directory.VirtualAddress + offset, |
| 170 sizeof(debug_directory), | 136 sizeof(debug_directory), |
| 171 &debug_directory)) { | 137 &debug_directory)) { |
| 172 LOG(WARNING) << "could not read data directory"; | 138 LOG(WARNING) << "could not read data directory"; |
| 173 return false; | 139 return false; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 // This occurs for non-PDB based debug information. We simply ignore these | 175 // This occurs for non-PDB based debug information. We simply ignore these |
| 210 // as we don't expect to encounter modules that will be in this format | 176 // as we don't expect to encounter modules that will be in this format |
| 211 // for which we'll actually have symbols. See | 177 // for which we'll actually have symbols. See |
| 212 // https://crashpad.chromium.org/bug/47. | 178 // https://crashpad.chromium.org/bug/47. |
| 213 } | 179 } |
| 214 } | 180 } |
| 215 | 181 |
| 216 return false; | 182 return false; |
| 217 } | 183 } |
| 218 | 184 |
| 185 bool PEImageReader::VSFixedFileInfo( | |
| 186 VS_FIXEDFILEINFO* vs_fixed_file_info) const { | |
| 187 IMAGE_DATA_DIRECTORY data_directory; | |
| 188 if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE, | |
| 189 &data_directory)) { | |
| 190 return false; | |
| 191 } | |
| 192 | |
| 193 PEImageResourceReader resource_reader; | |
| 194 if (!resource_reader.Initialize( | |
| 195 process_reader_, data_directory, module_range_, module_name_)) { | |
| 196 return false; | |
| 197 } | |
| 198 | |
| 199 WinVMAddress address; | |
| 200 WinVMSize size; | |
| 201 if (!resource_reader.FindResourceByID( | |
| 202 reinterpret_cast<uint16_t>(VS_FILE_INFO), | |
| 203 VS_VERSION_INFO, | |
| 204 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), | |
| 205 &address, | |
| 206 &size, | |
| 207 nullptr)) { | |
| 208 return false; | |
| 209 } | |
| 210 | |
| 211 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001.aspx | |
| 212 struct VS_VERSIONINFO { | |
| 213 WORD wLength; | |
| 214 WORD wValueLength; | |
| 215 WORD wType; | |
| 216 | |
| 217 // MSDN doesn’t show the [16], but this is in fact a 16-character string. | |
| 218 WCHAR szKey[16]; | |
| 219 | |
| 220 WORD Padding1; | |
| 221 VS_FIXEDFILEINFO Value; | |
| 222 | |
| 223 // Don’t include Children or the Padding2 that precedes it, because they may | |
| 224 // not be present. | |
| 225 // WORD Padding2; | |
| 226 // WORD Children; | |
| 227 }; | |
| 228 VS_VERSIONINFO version_info; | |
| 229 | |
| 230 if (size < sizeof(version_info)) { | |
| 231 LOG(WARNING) << "version info size " << size | |
| 232 << " too small for structure of size " << sizeof(version_info) | |
| 233 << " in " << module_name_; | |
| 234 return false; | |
| 235 } | |
| 236 | |
| 237 if (!CheckedReadMemory(address, sizeof(version_info), &version_info)) { | |
| 238 return false; | |
| 239 } | |
| 240 | |
| 241 if (version_info.wLength < sizeof(version_info) || | |
| 242 version_info.wValueLength < sizeof(version_info.Value) || | |
|
scottmg
2015/11/26 21:29:59
!= for this one rather than <, as if it's not our
Mark Mentovai
2015/12/01 18:48:00
scottmg wrote:
| |
| 243 version_info.wType != 0 || | |
| 244 wcsncmp(version_info.szKey, | |
| 245 L"VS_VERSION_INFO", | |
| 246 arraysize(version_info.szKey)) != 0) { | |
| 247 LOG(WARNING) << "unexpected VS_VERSIONINFO"; | |
| 248 return false; | |
| 249 } | |
| 250 | |
| 251 if (version_info.Value.dwSignature != VS_FFI_SIGNATURE || | |
| 252 version_info.Value.dwStrucVersion != VS_FFI_STRUCVERSION) { | |
| 253 LOG(WARNING) << "unexpected VS_FIXEDFILEINFO"; | |
| 254 return false; | |
| 255 } | |
| 256 | |
| 257 *vs_fixed_file_info = version_info.Value; | |
| 258 vs_fixed_file_info->dwFileFlags &= vs_fixed_file_info->dwFileFlagsMask; | |
| 259 return true; | |
| 260 } | |
| 261 | |
| 219 template <class NtHeadersType> | 262 template <class NtHeadersType> |
| 220 bool PEImageReader::ReadNtHeaders(NtHeadersType* nt_headers, | 263 bool PEImageReader::ReadNtHeaders(NtHeadersType* nt_headers, |
| 221 WinVMAddress* nt_headers_address) const { | 264 WinVMAddress* nt_headers_address) const { |
| 222 IMAGE_DOS_HEADER dos_header; | 265 IMAGE_DOS_HEADER dos_header; |
| 223 if (!CheckedReadMemory(Address(), sizeof(IMAGE_DOS_HEADER), &dos_header)) { | 266 if (!CheckedReadMemory(Address(), sizeof(IMAGE_DOS_HEADER), &dos_header)) { |
| 224 LOG(WARNING) << "could not read dos header of " << module_name_; | 267 LOG(WARNING) << "could not read dos header of " << module_name_; |
| 225 return false; | 268 return false; |
| 226 } | 269 } |
| 227 | 270 |
| 228 if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) { | 271 if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 if (strncmp(reinterpret_cast<const char*>(section->Name), | 318 if (strncmp(reinterpret_cast<const char*>(section->Name), |
| 276 name.c_str(), | 319 name.c_str(), |
| 277 sizeof(section->Name)) == 0) { | 320 sizeof(section->Name)) == 0) { |
| 278 return true; | 321 return true; |
| 279 } | 322 } |
| 280 } | 323 } |
| 281 | 324 |
| 282 return false; | 325 return false; |
| 283 } | 326 } |
| 284 | 327 |
| 328 bool PEImageReader::ImageDataDirectoryEntry(size_t index, | |
| 329 IMAGE_DATA_DIRECTORY* entry) const { | |
| 330 bool rv; | |
| 331 if (process_reader_->Is64Bit()) { | |
| 332 rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS64>(index, entry); | |
| 333 } else { | |
| 334 rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS32>(index, entry); | |
| 335 } | |
| 336 | |
| 337 return rv && entry->VirtualAddress != 0 && entry->Size != 0; | |
| 338 } | |
| 339 | |
| 340 template <class NtHeadersType> | |
| 341 bool PEImageReader::ImageDataDirectoryEntryT( | |
| 342 size_t index, | |
| 343 IMAGE_DATA_DIRECTORY* entry) const { | |
| 344 NtHeadersType nt_headers; | |
| 345 if (!ReadNtHeaders(&nt_headers, nullptr)) { | |
| 346 return false; | |
| 347 } | |
| 348 | |
| 349 if (nt_headers.FileHeader.SizeOfOptionalHeader < | |
| 350 offsetof(decltype(nt_headers.OptionalHeader), DataDirectory[index]) + | |
| 351 sizeof(nt_headers.OptionalHeader.DataDirectory[index]) || | |
| 352 nt_headers.OptionalHeader.NumberOfRvaAndSizes <= index) { | |
| 353 return false; | |
| 354 } | |
| 355 | |
| 356 *entry = nt_headers.OptionalHeader.DataDirectory[index]; | |
| 357 return true; | |
| 358 } | |
| 359 | |
| 285 bool PEImageReader::CheckedReadMemory(WinVMAddress address, | 360 bool PEImageReader::CheckedReadMemory(WinVMAddress address, |
| 286 WinVMSize size, | 361 WinVMSize size, |
| 287 void* into) const { | 362 void* into) const { |
| 288 CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size); | 363 CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size); |
| 289 if (!read_range.IsValid()) { | 364 if (!read_range.IsValid()) { |
| 290 LOG(WARNING) << "invalid read range: " << RangeToString(read_range); | 365 LOG(WARNING) << "invalid read range: " << read_range.AsString(); |
| 291 return false; | 366 return false; |
| 292 } | 367 } |
| 293 if (!module_range_.ContainsRange(read_range)) { | 368 if (!module_range_.ContainsRange(read_range)) { |
| 294 LOG(WARNING) << "attempt to read outside of module " << module_name_ | 369 LOG(WARNING) << "attempt to read outside of module " << module_name_ |
| 295 << " at range: " << RangeToString(read_range); | 370 << " at range: " << read_range.AsString(); |
| 296 return false; | 371 return false; |
| 297 } | 372 } |
| 298 return process_reader_->ReadMemory(address, size, into); | 373 return process_reader_->ReadMemory(address, size, into); |
| 299 } | 374 } |
| 300 | 375 |
| 301 // Explicit instantiations with the only 2 valid template arguments to avoid | 376 // Explicit instantiations with the only 2 valid template arguments to avoid |
| 302 // putting the body of the function in the header. | 377 // putting the body of the function in the header. |
| 303 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits32>( | 378 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits32>( |
| 304 process_types::CrashpadInfo<process_types::internal::Traits32>* | 379 process_types::CrashpadInfo<process_types::internal::Traits32>* |
| 305 crashpad_info) const; | 380 crashpad_info) const; |
| 306 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits64>( | 381 template bool PEImageReader::GetCrashpadInfo<process_types::internal::Traits64>( |
| 307 process_types::CrashpadInfo<process_types::internal::Traits64>* | 382 process_types::CrashpadInfo<process_types::internal::Traits64>* |
| 308 crashpad_info) const; | 383 crashpad_info) const; |
| 309 | 384 |
| 310 } // namespace crashpad | 385 } // namespace crashpad |
| OLD | NEW |