Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: src/processor/exploitability_linux.cc

Issue 1233973002: Add ELF header analysis when checking for instruction pointer in code. (Closed) Base URL: http://google-breakpad.googlecode.com/svn/trunk/
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 Google Inc. 1 // Copyright (c) 2013 Google Inc.
2 // All rights reserved. 2 // All rights reserved.
3 // 3 //
4 // Redistribution and use in source and binary forms, with or without 4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are 5 // modification, are permitted provided that the following conditions are
6 // met: 6 // met:
7 // 7 //
8 // * Redistributions of source code must retain the above copyright 8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer. 9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above 10 // * Redistributions in binary form must reproduce the above
(...skipping 18 matching lines...) Expand all
29 29
30 // exploitability_linux.cc: Linux specific exploitability engine. 30 // exploitability_linux.cc: Linux specific exploitability engine.
31 // 31 //
32 // Provides a guess at the exploitability of the crash for the Linux 32 // Provides a guess at the exploitability of the crash for the Linux
33 // platform given a minidump and process_state. 33 // platform given a minidump and process_state.
34 // 34 //
35 // Author: Matthew Riley 35 // Author: Matthew Riley
36 36
37 #include "processor/exploitability_linux.h" 37 #include "processor/exploitability_linux.h"
38 38
39 #include <assert.h>
40 #include <elf.h>
41 #include <stdlib.h>
42 #include <string.h>
43
39 #include "google_breakpad/common/minidump_exception_linux.h" 44 #include "google_breakpad/common/minidump_exception_linux.h"
40 #include "google_breakpad/processor/call_stack.h" 45 #include "google_breakpad/processor/call_stack.h"
41 #include "google_breakpad/processor/process_state.h" 46 #include "google_breakpad/processor/process_state.h"
42 #include "google_breakpad/processor/stack_frame.h" 47 #include "google_breakpad/processor/stack_frame.h"
43 #include "processor/logging.h" 48 #include "processor/logging.h"
44 49
45 namespace { 50 namespace {
46 51
47 // This function in libc is called if the program was compiled with 52 // This function in libc is called if the program was compiled with
48 // -fstack-protector and a function's stack canary changes. 53 // -fstack-protector and a function's stack canary changes.
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 // Getting the instruction pointer. 117 // Getting the instruction pointer.
113 if (!context->GetInstructionPointer(&instruction_ptr)) { 118 if (!context->GetInstructionPointer(&instruction_ptr)) {
114 return EXPLOITABILITY_ERR_PROCESSING; 119 return EXPLOITABILITY_ERR_PROCESSING;
115 } 120 }
116 121
117 // Checking for the instruction pointer in a valid instruction region. 122 // Checking for the instruction pointer in a valid instruction region.
118 if (!this->InstructionPointerInCode(instruction_ptr)) { 123 if (!this->InstructionPointerInCode(instruction_ptr)) {
119 return EXPLOITABILITY_HIGH; 124 return EXPLOITABILITY_HIGH;
120 } 125 }
121 126
127 // There was no strong evidence suggesting exploitability, but the minidump
128 // does not appear totally benign either.
122 return EXPLOITABILITY_INTERESTING; 129 return EXPLOITABILITY_INTERESTING;
123 } 130 }
124 131
132 bool ExploitabilityLinux::Architecture32Bit() {
133 // GetContextCPU() should have already been successfully called before
ahonig 2015/07/14 19:32:18 Add a check to make sure this is the case. If the
liuandrew 2015/07/15 21:50:14 Done.
134 // calling this method. Thus the switch statement should not seg fault.
135 switch (dump_->GetException()->GetContext()->GetContextCPU()) {
136 case MD_CONTEXT_ARM:
137 case MD_CONTEXT_X86:
138 return true;
139 case MD_CONTEXT_ARM64:
140 case MD_CONTEXT_AMD64:
141 return false;
142 default:
143 // This should not happen. The four architectures above should be
144 // the only Linux architectures.
145 BPLOG(INFO) << "Unsupported architecture.";
ivanpe 2015/07/14 00:23:02 Instead of bool, you should consider returning an
liuandrew 2015/07/15 21:50:14 Done.
146 return false;
147 }
148 }
149
125 bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) { 150 bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) {
126 // Here we get memory mapping. Most minidumps will not contain a memory 151 // Here we get memory mapping. Most minidumps will not contain a memory
127 // mapping, so we will commonly resort to checking modules. 152 // mapping, so we will commonly resort to checking modules.
128 MinidumpMemoryInfoList *mem_info_list = dump_->GetMemoryInfoList(); 153 MinidumpMemoryInfoList *mem_info_list = dump_->GetMemoryInfoList();
129 const MinidumpMemoryInfo *mem_info = 154 const MinidumpMemoryInfo *mem_info =
130 mem_info_list ? 155 mem_info_list ?
131 mem_info_list->GetMemoryInfoForAddress(instruction_ptr) : NULL; 156 mem_info_list->GetMemoryInfoForAddress(instruction_ptr) : NULL;
132 157
133 // Checking if the memory mapping at the instruction pointer is executable. 158 // Checking if the memory mapping at the instruction pointer is executable.
134 // If there is no memory mapping, we will use the modules as reference. 159 // If there is no memory mapping, we will use the modules as reference.
135 if (mem_info != NULL) { 160 if (mem_info != NULL) {
136 return mem_info->IsExecutable(); 161 return mem_info->IsExecutable();
137 } 162 }
138 163
139 // If the memory mapping retrieval fails, we will check the modules 164 // If the memory mapping retrieval fails, we will check the modules
140 // to see if the instruction pointer is inside a module. 165 // to see if the instruction pointer is inside a module.
141 // TODO(liuandrew): Check if the instruction pointer lies in an executable
142 // region within the module.
143 MinidumpModuleList *minidump_module_list = dump_->GetModuleList(); 166 MinidumpModuleList *minidump_module_list = dump_->GetModuleList();
144 return !minidump_module_list || 167 const MinidumpModule *minidump_module =
145 minidump_module_list->GetModuleForAddress(instruction_ptr); 168 minidump_module_list ?
169 minidump_module_list->GetModuleForAddress(instruction_ptr) : NULL;
170
171 // If the instruction pointer isn't in a module, we can return false.
ivanpe 2015/07/14 00:23:02 Please, don't use "we" in comments. Comments shoul
liuandrew 2015/07/15 21:50:14 Done.
172 if (minidump_module == NULL) {
173 return false;
174 }
175
176 // Get ELF header data from the instruction pointer's module.
177 const uint64_t base_address = minidump_module->base_address();
178 MinidumpMemoryList *memory_list = dump_->GetMemoryList();
179 MinidumpMemoryRegion *memory_region =
180 memory_list ?
181 memory_list->GetMemoryRegionForAddress(base_address) : NULL;
182
183 // The minidump does not have the correct memory region.
184 // This returns true because even though there is no memory data available,
185 // the evidence so far suggests that the instruction pointer is not at a
186 // bad location.
187 if (memory_region == NULL) {
188 return true;
189 }
190
191 // Examine ELF headers. Depending on the architecture, the size of the
192 // ELF headers can differ.
193 if (this->Architecture32Bit()) {
194 // Check if the ELF header is within the memory region.
195 if (memory_region->GetSize() < sizeof(Elf32_Phdr)) {
196 return false;
197 }
198 // Set 32-bit ELF header and program header table.
ivanpe 2015/07/14 00:23:02 Instead of "Set" maybe is s better to say "Load" o
liuandrew 2015/07/15 21:50:14 Done.
199 Elf32_Ehdr *header = this->LoadElf32Header(memory_region, base_address);
ivanpe 2015/07/14 00:23:02 Do we need to worry about ownership transfer here?
liuandrew 2015/07/15 21:50:13 using scoped_ptr
200 assert(header->e_phentsize == sizeof(Elf32_Phdr));
ahonig 2015/07/14 19:32:18 assert is compiled out in non-debug builds. If th
liuandrew 2015/07/15 21:50:14 Done.
201 // Check if the program header table is within the memory region.
202 if (memory_region->GetSize() <
203 header->e_phoff + (header->e_phentsize * header->e_phnum)) {
204 return false;
205 }
206
207 Elf32_Phdr *program_headers = this->LoadElf32PHeader(memory_region,
208 base_address,
209 header->e_phoff,
210 header->e_phentsize,
211 header->e_phnum);
212 // Find correct program header that corresponds to the instruction pointer.
213 for (int i = 0; i < header->e_phnum; i++) {
214 Elf32_Phdr program_header = program_headers[i];
ivanpe 2015/07/14 00:23:02 Please, use const Elf32_Phdr& to avoid copy
215 // Check if instruction pointer lies within this program header's region.
216 if (program_header.p_vaddr >= instruction_ptr &&
217 program_header.p_vaddr + program_header.p_memsz < instruction_ptr) {
ivanpe 2015/07/14 00:23:02 This check seems wrong to me. It can only be true
liuandrew 2015/07/15 21:50:14 My bad. I flipped the equality signs. Fixed and ad
218 free(header);
ivanpe 2015/07/14 00:23:01 I noticed that you free header here but you don't
ahonig 2015/07/14 19:32:18 The pattern of free is pretty complicated and erro
liuandrew 2015/07/15 21:50:14 Done.
219 free(program_headers);
220 // Return whether this program header region is executable.
221 return program_header.p_flags & 1;
ivanpe 2015/07/14 00:23:01 Instead of the literal 1, isn't there a constant t
liuandrew 2015/07/15 21:50:14 Done.
222 }
223 }
224 free(header);
225 free(program_headers);
226 } else {
227 // Check if the ELF header is within the memory region.
228 if (memory_region->GetSize() < sizeof(Elf64_Phdr)) {
229 return false;
230 }
231 // Set 64-bit ELF header and program header table.
232 Elf64_Ehdr *header = this->LoadElf64Header(memory_region, base_address);
233 assert(header->e_phentsize == sizeof(Elf64_Phdr));
234 // Check if the program header table is within the memory region.
235 if (memory_region->GetSize() <
236 header->e_phoff + (header->e_phentsize * header->e_phnum)) {
237 return false;
238 }
239 Elf64_Phdr *program_headers = this->LoadElf64PHeader(memory_region,
240 base_address,
241 header->e_phoff,
242 header->e_phentsize,
243 header->e_phnum);
244 // Find correct program header that corresponds to the instruction pointer.
245 for (int i = 0; i < header->e_phnum; i++) {
246 Elf64_Phdr program_header = program_headers[i];
247 // Check if instruction pointer lies within this program header's region.
248 if (program_header.p_vaddr >= instruction_ptr &&
249 program_header.p_vaddr + program_header.p_memsz < instruction_ptr) {
250 free(header);
251 free(program_headers);
252 // Return whether this program header region is executable.
253 return program_header.p_flags & 1;
254 }
255 }
256 free(header);
257 free(program_headers);
258 }
259
260 // The instruction pointer was not in an area identified by the ELF headers.
261 return false;
262 }
263
264 void *ExploitabilityLinux::LoadElfHeader(MinidumpMemoryRegion *memory,
ivanpe 2015/07/14 00:23:02 I would suggest replacing this with a template met
liuandrew 2015/07/15 21:50:14 Done.
265 const uint64_t base_address,
266 size_t header_size) {
267 void *header = malloc(header_size);
268 // Copy over each byte.
269 for (size_t i = 0; i < header_size; i++) {
270 uint8_t my_byte = 0;
271 // Get the value at the memory address.
272 memory->GetMemoryAtAddress(base_address + i, &my_byte);
273 memcpy(reinterpret_cast<char *>(header) + i, &my_byte, sizeof(uint8_t));
274 }
275 return header;
276 }
277
278 Elf32_Ehdr *ExploitabilityLinux::LoadElf32Header(MinidumpMemoryRegion *memory,
279 const uint64_t base_address) {
280 return reinterpret_cast<Elf32_Ehdr *>(LoadElfHeader(memory,
281 base_address,
282 sizeof(Elf32_Ehdr)));
283 }
284
285 Elf64_Ehdr *ExploitabilityLinux::LoadElf64Header(MinidumpMemoryRegion *memory,
286 const uint64_t base_address) {
287 return reinterpret_cast<Elf64_Ehdr *>(LoadElfHeader(memory,
288 base_address,
289 sizeof(Elf64_Ehdr)));
290 }
291
292 Elf32_Phdr *ExploitabilityLinux::LoadElf32PHeader(MinidumpMemoryRegion *memory,
293 const uint64_t base_address,
294 const uint64_t e_phoff,
295 const uint16_t e_phentsize,
296 const uint16_t e_phnum) {
297 // The base address with the offset makes the starting memory address.
298 // The entry size multiplied by the number of entries is the number of bytes.
299 return reinterpret_cast<Elf32_Phdr *>(LoadElfHeader(memory,
300 (base_address + e_phoff),
301 (e_phentsize * e_phnum)));
302 }
303
304 Elf64_Phdr *ExploitabilityLinux::LoadElf64PHeader(MinidumpMemoryRegion *memory,
305 const uint64_t base_address,
306 const uint64_t e_phoff,
307 const uint16_t e_phentsize,
308 const uint16_t e_phnum) {
309 // The base address with the offset makes the starting memory address.
310 // The entry size multiplied by the number of entries is the number of bytes.
311 return reinterpret_cast<Elf64_Phdr *>(LoadElfHeader(memory,
312 (base_address + e_phoff),
313 (e_phentsize * e_phnum)));
146 } 314 }
147 315
148 bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream 316 bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream
149 *raw_exception_stream) { 317 *raw_exception_stream) {
150 // Here we check the cause of crash. 318 // Here we check the cause of crash.
151 // If the exception of the crash is a benign exception, 319 // If the exception of the crash is a benign exception,
152 // it is probably not exploitable. 320 // it is probably not exploitable.
153 switch (raw_exception_stream->exception_record.exception_code) { 321 switch (raw_exception_stream->exception_record.exception_code) {
154 case MD_EXCEPTION_CODE_LIN_SIGHUP: 322 case MD_EXCEPTION_CODE_LIN_SIGHUP:
155 case MD_EXCEPTION_CODE_LIN_SIGINT: 323 case MD_EXCEPTION_CODE_LIN_SIGINT:
(...skipping 25 matching lines...) Expand all
181 case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: 349 case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
182 return true; 350 return true;
183 break; 351 break;
184 default: 352 default:
185 return false; 353 return false;
186 break; 354 break;
187 } 355 }
188 } 356 }
189 357
190 } // namespace google_breakpad 358 } // namespace google_breakpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698