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 |