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

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

Powered by Google App Engine
This is Rietveld 408576698