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

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
« no previous file with comments | « src/processor/exploitability_linux.h ('k') | src/processor/exploitability_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <elf.h>
40
39 #include "google_breakpad/common/minidump_exception_linux.h" 41 #include "google_breakpad/common/minidump_exception_linux.h"
40 #include "google_breakpad/processor/call_stack.h" 42 #include "google_breakpad/processor/call_stack.h"
41 #include "google_breakpad/processor/process_state.h" 43 #include "google_breakpad/processor/process_state.h"
42 #include "google_breakpad/processor/stack_frame.h" 44 #include "google_breakpad/processor/stack_frame.h"
43 #include "processor/logging.h" 45 #include "processor/logging.h"
44 46
45 namespace { 47 namespace {
46 48
47 // This function in libc is called if the program was compiled with 49 // This function in libc is called if the program was compiled with
48 // -fstack-protector and a function's stack canary changes. 50 // -fstack-protector and a function's stack canary changes.
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 // Check if the instruction pointer is in a valid instruction region 104 // Check if the instruction pointer is in a valid instruction region
103 // by finding if it maps to an executable part of memory. 105 // by finding if it maps to an executable part of memory.
104 uint64_t instruction_ptr = 0; 106 uint64_t instruction_ptr = 0;
105 107
106 const MinidumpContext *context = exception->GetContext(); 108 const MinidumpContext *context = exception->GetContext();
107 if (context == NULL) { 109 if (context == NULL) {
108 BPLOG(INFO) << "No exception context."; 110 BPLOG(INFO) << "No exception context.";
109 return EXPLOITABILITY_ERR_PROCESSING; 111 return EXPLOITABILITY_ERR_PROCESSING;
110 } 112 }
111 113
114 if (this->ArchitectureType() == UNSUPPORTED_ARCHITECTURE) {
115 BPLOG(INFO) << "Unsupported architecture.";
116 return EXPLOITABILITY_ERR_PROCESSING;
117 }
112 // Getting the instruction pointer. 118 // Getting the instruction pointer.
113 if (!context->GetInstructionPointer(&instruction_ptr)) { 119 if (!context->GetInstructionPointer(&instruction_ptr)) {
120 BPLOG(INFO) << "Failed to retrieve instruction pointer.";
114 return EXPLOITABILITY_ERR_PROCESSING; 121 return EXPLOITABILITY_ERR_PROCESSING;
115 } 122 }
116 123
117 // Checking for the instruction pointer in a valid instruction region. 124 // Checking for the instruction pointer in a valid instruction region.
118 if (!this->InstructionPointerInCode(instruction_ptr)) { 125 if (!this->InstructionPointerInCode(instruction_ptr)) {
119 return EXPLOITABILITY_HIGH; 126 return EXPLOITABILITY_HIGH;
120 } 127 }
121 128
129 // There was no strong evidence suggesting exploitability, but the minidump
130 // does not appear totally benign either.
122 return EXPLOITABILITY_INTERESTING; 131 return EXPLOITABILITY_INTERESTING;
123 } 132 }
124 133
134 LinuxArchitectureType ExploitabilityLinux::ArchitectureType() {
135 // GetContextCPU() should have already been successfully called before
136 // calling this method. Thus there should be a raw exception stream for
137 // the minidump.
138 MinidumpException *exception = dump_->GetException();
139 const DumpContext *dump_context =
140 exception ?
141 exception->GetContext() : NULL;
142 if (dump_context == NULL) {
143 BPLOG(INFO) << "No raw dump context.";
144 return UNSUPPORTED_ARCHITECTURE;
145 }
146
147 // Check the architecture type.
148 switch (dump_context->GetContextCPU()) {
149 case MD_CONTEXT_ARM:
150 case MD_CONTEXT_X86:
151 return LINUX_32_BIT;
152 case MD_CONTEXT_ARM64:
153 case MD_CONTEXT_AMD64:
154 return LINUX_64_BIT;
155 default:
156 // This should not happen. The four architectures above should be
157 // the only Linux architectures.
158 BPLOG(INFO) << "Unsupported architecture.";
159 return UNSUPPORTED_ARCHITECTURE;
160 }
161 }
162
125 bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) { 163 bool ExploitabilityLinux::InstructionPointerInCode(uint64_t instruction_ptr) {
126 // Here we get memory mapping. Most minidumps will not contain a memory 164 // Get memory mapping. Most minidumps will not contain a memory
127 // mapping, so we will commonly resort to checking modules. 165 // mapping, so processing will commonly resort to checking modules.
128 MinidumpMemoryInfoList *mem_info_list = dump_->GetMemoryInfoList(); 166 MinidumpMemoryInfoList *mem_info_list = dump_->GetMemoryInfoList();
129 const MinidumpMemoryInfo *mem_info = 167 const MinidumpMemoryInfo *mem_info =
130 mem_info_list ? 168 mem_info_list ?
131 mem_info_list->GetMemoryInfoForAddress(instruction_ptr) : NULL; 169 mem_info_list->GetMemoryInfoForAddress(instruction_ptr) : NULL;
132 170
133 // Checking if the memory mapping at the instruction pointer is executable. 171 // Check if the memory mapping at the instruction pointer is executable.
134 // If there is no memory mapping, we will use the modules as reference. 172 // If there is no memory mapping, processing will use modules as reference.
135 if (mem_info != NULL) { 173 if (mem_info != NULL) {
136 return mem_info->IsExecutable(); 174 return mem_info->IsExecutable();
137 } 175 }
138 176
139 // If the memory mapping retrieval fails, we will check the modules 177 // If the memory mapping retrieval fails, check the modules
140 // to see if the instruction pointer is inside a module. 178 // 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(); 179 MinidumpModuleList *minidump_module_list = dump_->GetModuleList();
144 return !minidump_module_list || 180 const MinidumpModule *minidump_module =
145 minidump_module_list->GetModuleForAddress(instruction_ptr); 181 minidump_module_list ?
182 minidump_module_list->GetModuleForAddress(instruction_ptr) : NULL;
183
184 // If the instruction pointer isn't in a module, return false.
185 if (minidump_module == NULL) {
186 return false;
187 }
188
189 // Get ELF header data from the instruction pointer's module.
190 const uint64_t base_address = minidump_module->base_address();
191 MinidumpMemoryList *memory_list = dump_->GetMemoryList();
192 MinidumpMemoryRegion *memory_region =
193 memory_list ?
194 memory_list->GetMemoryRegionForAddress(base_address) : NULL;
195
196 // The minidump does not have the correct memory region.
197 // This returns true because even though there is no memory data available,
198 // the evidence so far suggests that the instruction pointer is not at a
199 // bad location.
200 if (memory_region == NULL) {
201 return true;
202 }
203
204 // Examine ELF headers. Depending on the architecture, the size of the
205 // ELF headers can differ.
206 LinuxArchitectureType architecture = this->ArchitectureType();
207 if (architecture == LINUX_32_BIT) {
208 // Check if the ELF header is within the memory region and if the
209 // instruction pointer lies within the ELF header.
210 if (memory_region->GetSize() < sizeof(Elf32_Ehdr) ||
211 instruction_ptr < base_address + sizeof(Elf32_Ehdr)) {
212 return false;
213 }
214 // Load 32-bit ELF header.
215 Elf32_Ehdr header;
216 this->LoadElfHeader(memory_region, base_address, &header);
217 // Check if the program header table is within the memory region, and
218 // validate that the program header entry size is correct.
219 if (header.e_phentsize != sizeof(Elf32_Phdr) ||
220 memory_region->GetSize() <
221 header.e_phoff +
222 ((uint64_t) header.e_phentsize * (uint64_t) header.e_phnum)) {
223 return false;
224 }
225 // Load 32-bit Program Header Table.
226 scoped_array<Elf32_Phdr> program_headers(new Elf32_Phdr[header.e_phnum]);
227 this->LoadElfHeaderTable(memory_region,
228 base_address + header.e_phoff,
229 header.e_phnum,
230 program_headers.get());
231 // Find correct program header that corresponds to the instruction pointer.
232 for (int i = 0; i < header.e_phnum; i++) {
233 const Elf32_Phdr& program_header = program_headers[i];
234 // Check if instruction pointer lies within this program header's region.
235 if (instruction_ptr >= program_header.p_vaddr &&
236 instruction_ptr < program_header.p_vaddr + program_header.p_memsz) {
237 // Return whether this program header region is executable.
238 return program_header.p_flags & PF_X;
239 }
240 }
241 } else if (architecture == LINUX_64_BIT) {
242 // Check if the ELF header is within the memory region and if the
243 // instruction pointer lies within the ELF header.
244 if (memory_region->GetSize() < sizeof(Elf64_Ehdr) ||
245 instruction_ptr < base_address + sizeof(Elf64_Ehdr)) {
246 return false;
247 }
248 // Load 64-bit ELF header.
249 Elf64_Ehdr header;
250 this->LoadElfHeader(memory_region, base_address, &header);
251 // Check if the program header table is within the memory region, and
252 // validate that the program header entry size is correct.
253 if (header.e_phentsize != sizeof(Elf64_Phdr) ||
254 memory_region->GetSize() <
255 header.e_phoff +
256 ((uint64_t) header.e_phentsize * (uint64_t) header.e_phnum)) {
257 return false;
258 }
259 // Load 64-bit Program Header Table.
260 scoped_array<Elf64_Phdr> program_headers(new Elf64_Phdr[header.e_phnum]);
261 this->LoadElfHeaderTable(memory_region,
262 base_address + header.e_phoff,
263 header.e_phnum,
264 program_headers.get());
265 // Find correct program header that corresponds to the instruction pointer.
266 for (int i = 0; i < header.e_phnum; i++) {
267 const Elf64_Phdr& program_header = program_headers[i];
268 // Check if instruction pointer lies within this program header's region.
269 if (instruction_ptr >= program_header.p_vaddr &&
270 instruction_ptr < program_header.p_vaddr + program_header.p_memsz) {
271 // Return whether this program header region is executable.
272 return program_header.p_flags & PF_X;
273 }
274 }
275 }
276
277 // The instruction pointer was not in an area identified by the ELF headers.
278 return false;
146 } 279 }
147 280
148 bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream 281 bool ExploitabilityLinux::BenignCrashTrigger(const MDRawExceptionStream
149 *raw_exception_stream) { 282 *raw_exception_stream) {
150 // Here we check the cause of crash. 283 // Check the cause of crash.
151 // If the exception of the crash is a benign exception, 284 // If the exception of the crash is a benign exception,
152 // it is probably not exploitable. 285 // it is probably not exploitable.
153 switch (raw_exception_stream->exception_record.exception_code) { 286 switch (raw_exception_stream->exception_record.exception_code) {
154 case MD_EXCEPTION_CODE_LIN_SIGHUP: 287 case MD_EXCEPTION_CODE_LIN_SIGHUP:
155 case MD_EXCEPTION_CODE_LIN_SIGINT: 288 case MD_EXCEPTION_CODE_LIN_SIGINT:
156 case MD_EXCEPTION_CODE_LIN_SIGQUIT: 289 case MD_EXCEPTION_CODE_LIN_SIGQUIT:
157 case MD_EXCEPTION_CODE_LIN_SIGTRAP: 290 case MD_EXCEPTION_CODE_LIN_SIGTRAP:
158 case MD_EXCEPTION_CODE_LIN_SIGABRT: 291 case MD_EXCEPTION_CODE_LIN_SIGABRT:
159 case MD_EXCEPTION_CODE_LIN_SIGFPE: 292 case MD_EXCEPTION_CODE_LIN_SIGFPE:
160 case MD_EXCEPTION_CODE_LIN_SIGKILL: 293 case MD_EXCEPTION_CODE_LIN_SIGKILL:
(...skipping 20 matching lines...) Expand all
181 case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: 314 case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
182 return true; 315 return true;
183 break; 316 break;
184 default: 317 default:
185 return false; 318 return false;
186 break; 319 break;
187 } 320 }
188 } 321 }
189 322
190 } // namespace google_breakpad 323 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « src/processor/exploitability_linux.h ('k') | src/processor/exploitability_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698