xref: /aosp_15_r20/external/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 // linux_dumper.cc: Implement google_breakpad::LinuxDumper.
30 // See linux_dumper.h for details.
31 
32 // This code deals with the mechanics of getting information about a crashed
33 // process. Since this code may run in a compromised address space, the same
34 // rules apply as detailed at the top of minidump_writer.h: no libc calls and
35 // use the alternative allocator.
36 
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>  // Must come first
39 #endif
40 
41 #include "client/linux/minidump_writer/linux_dumper.h"
42 
43 #include <assert.h>
44 #include <elf.h>
45 #include <fcntl.h>
46 #include <limits.h>
47 #include <stddef.h>
48 #include <string.h>
49 
50 #include "client/linux/minidump_writer/line_reader.h"
51 #include "common/linux/elfutils.h"
52 #include "common/linux/file_id.h"
53 #include "common/linux/linux_libc_support.h"
54 #include "common/linux/memory_mapped_file.h"
55 #include "common/linux/safe_readlink.h"
56 #include "google_breakpad/common/minidump_exception_linux.h"
57 #include "third_party/lss/linux_syscall_support.h"
58 
59 using google_breakpad::elf::FileID;
60 
61 #if defined(__ANDROID__)
62 
63 // Android packed relocations definitions are not yet available from the
64 // NDK header files, so we have to provide them manually here.
65 #ifndef DT_LOOS
66 #define DT_LOOS 0x6000000d
67 #endif
68 #ifndef DT_ANDROID_REL
69 static const int DT_ANDROID_REL = DT_LOOS + 2;
70 #endif
71 #ifndef DT_ANDROID_RELA
72 static const int DT_ANDROID_RELA = DT_LOOS + 4;
73 #endif
74 
75 #endif  // __ANDROID __
76 
77 static const char kMappedFileUnsafePrefix[] = "/dev/";
78 static const char kDeletedSuffix[] = " (deleted)";
79 
IsMappedFileOpenUnsafe(const google_breakpad::MappingInfo & mapping)80 inline static bool IsMappedFileOpenUnsafe(
81     const google_breakpad::MappingInfo& mapping) {
82   // It is unsafe to attempt to open a mapped file that lives under /dev,
83   // because the semantics of the open may be driver-specific so we'd risk
84   // hanging the crash dumper. And a file in /dev/ almost certainly has no
85   // ELF file identifier anyways.
86   return my_strncmp(mapping.name,
87                     kMappedFileUnsafePrefix,
88                     sizeof(kMappedFileUnsafePrefix) - 1) == 0;
89 }
90 
91 namespace google_breakpad {
92 
93 namespace {
94 
MappingContainsAddress(const MappingInfo & mapping,uintptr_t address)95 bool MappingContainsAddress(const MappingInfo& mapping, uintptr_t address) {
96   return mapping.system_mapping_info.start_addr <= address &&
97          address < mapping.system_mapping_info.end_addr;
98 }
99 
100 #if defined(__CHROMEOS__)
101 
102 // Recover memory mappings before writing dump on ChromeOS
103 //
104 // On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from
105 // addresses. ChromeOS' hugepage implementation replaces some segments with
106 // anonymous private pages, which is a restriction of current implementation
107 // in Linux kernel at the time of writing. Thus, breakpad can no longer
108 // symbolize addresses from those text segments replaced with hugepages.
109 //
110 // This postprocess tries to recover the mappings. Because hugepages are always
111 // inserted in between some .text sections, it tries to infer the names and
112 // offsets of the segments, by looking at segments immediately precede and
113 // succeed them.
114 //
115 // For example, a text segment before hugepage optimization
116 //   02001000-03002000 r-xp /opt/google/chrome/chrome
117 //
118 // can be broken into
119 //   02001000-02200000 r-xp /opt/google/chrome/chrome
120 //   02200000-03000000 r-xp
121 //   03000000-03002000 r-xp /opt/google/chrome/chrome
122 //
123 // For more details, see:
124 // crbug.com/628040 ChromeOS' use of hugepages confuses crash symbolization
125 
126 // Copied from CrOS' hugepage implementation, which is unlikely to change.
127 // The hugepage size is 2M.
128 const unsigned int kHpageShift = 21;
129 const size_t kHpageSize = (1 << kHpageShift);
130 const size_t kHpageMask = (~(kHpageSize - 1));
131 
132 // Find and merge anonymous r-xp segments with surrounding named segments.
133 // There are two cases:
134 
135 // Case 1: curr, next
136 //   curr is anonymous
137 //   curr is r-xp
138 //   curr.size >= 2M
139 //   curr.size is a multiple of 2M.
140 //   next is backed by some file.
141 //   curr and next are contiguous.
142 //   offset(next) == sizeof(curr)
TryRecoverMappings(MappingInfo * curr,MappingInfo * next)143 void TryRecoverMappings(MappingInfo* curr, MappingInfo* next) {
144   // Merged segments are marked with size = 0.
145   if (curr->size == 0 || next->size == 0)
146     return;
147 
148   if (curr->size >= kHpageSize &&
149       curr->exec &&
150       (curr->size & kHpageMask) == curr->size &&
151       (curr->start_addr & kHpageMask) == curr->start_addr &&
152       curr->name[0] == '\0' &&
153       next->name[0] != '\0' &&
154       curr->start_addr + curr->size == next->start_addr &&
155       curr->size == next->offset) {
156 
157     // matched
158     my_strlcpy(curr->name, next->name, NAME_MAX);
159     if (next->exec) {
160       // (curr, next)
161       curr->size += next->size;
162       next->size = 0;
163     }
164   }
165 }
166 
167 // Case 2: prev, curr, next
168 //   curr is anonymous
169 //   curr is r-xp
170 //   curr.size >= 2M
171 //   curr.size is a multiple of 2M.
172 //   next and prev are backed by the same file.
173 //   prev, curr and next are contiguous.
174 //   offset(next) == offset(prev) + sizeof(prev) + sizeof(curr)
TryRecoverMappings(MappingInfo * prev,MappingInfo * curr,MappingInfo * next)175 void TryRecoverMappings(MappingInfo* prev, MappingInfo* curr,
176                         MappingInfo* next) {
177   // Merged segments are marked with size = 0.
178   if (prev->size == 0 || curr->size == 0 || next->size == 0)
179     return;
180 
181   if (curr->size >= kHpageSize &&
182       curr->exec &&
183       (curr->size & kHpageMask) == curr->size &&
184       (curr->start_addr & kHpageMask) == curr->start_addr &&
185       curr->name[0] == '\0' &&
186       next->name[0] != '\0' &&
187       curr->start_addr + curr->size == next->start_addr &&
188       prev->start_addr + prev->size == curr->start_addr &&
189       my_strncmp(prev->name, next->name, NAME_MAX) == 0 &&
190       next->offset == prev->offset + prev->size + curr->size) {
191 
192     // matched
193     my_strlcpy(curr->name, prev->name, NAME_MAX);
194     if (prev->exec) {
195       curr->offset = prev->offset;
196       curr->start_addr = prev->start_addr;
197       if (next->exec) {
198         // (prev, curr, next)
199         curr->size += prev->size + next->size;
200         prev->size = 0;
201         next->size = 0;
202       } else {
203         // (prev, curr), next
204         curr->size += prev->size;
205         prev->size = 0;
206       }
207     } else {
208       curr->offset = prev->offset + prev->size;
209       if (next->exec) {
210         // prev, (curr, next)
211         curr->size += next->size;
212         next->size = 0;
213       } else {
214         // prev, curr, next
215       }
216     }
217   }
218 }
219 
220 // mappings_ is sorted excepted for the first entry.
221 // This function tries to merge segemnts into the first entry,
222 // then check for other sorted entries.
223 // See LinuxDumper::EnumerateMappings().
CrOSPostProcessMappings(wasteful_vector<MappingInfo * > & mappings)224 void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) {
225   // Find the candidate "next" to first segment, which is the only one that
226   // could be out-of-order.
227   size_t l = 1;
228   size_t r = mappings.size();
229   size_t next = mappings.size();
230   while (l < r) {
231     int m = (l + r) / 2;
232     if (mappings[m]->start_addr > mappings[0]->start_addr)
233       r = next = m;
234     else
235       l = m + 1;
236   }
237 
238   // Shows the range that contains the entry point is
239   // [first_start_addr, first_end_addr)
240   size_t first_start_addr = mappings[0]->start_addr;
241   size_t first_end_addr = mappings[0]->start_addr + mappings[0]->size;
242 
243   // Put the out-of-order segment in order.
244   std::rotate(mappings.begin(), mappings.begin() + 1, mappings.begin() + next);
245 
246   // Iterate through normal, sorted cases.
247   // Normal case 1.
248   for (size_t i = 0; i < mappings.size() - 1; i++)
249     TryRecoverMappings(mappings[i], mappings[i + 1]);
250 
251   // Normal case 2.
252   for (size_t i = 0; i < mappings.size() - 2; i++)
253     TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]);
254 
255   // Collect merged (size == 0) segments.
256   size_t f, e;
257   for (f = e = 0; e < mappings.size(); e++)
258     if (mappings[e]->size > 0)
259       mappings[f++] = mappings[e];
260   mappings.resize(f);
261 
262   // The entry point is in the first mapping. We want to find the location
263   // of the entry point after merging segment. To do this, we want to find
264   // the mapping that covers the first mapping from the original mapping list.
265   // If the mapping is not in the beginning, we move it to the begining via
266   // a right rotate by using reverse iterators.
267   for (l = 0; l < mappings.size(); l++) {
268     if (mappings[l]->start_addr <= first_start_addr
269         && (mappings[l]->start_addr + mappings[l]->size >= first_end_addr))
270       break;
271   }
272   if (l > 0) {
273     r = mappings.size();
274     std::rotate(mappings.rbegin() + r - l - 1, mappings.rbegin() + r - l,
275                 mappings.rend());
276   }
277 }
278 
279 #endif  // __CHROMEOS__
280 
281 }  // namespace
282 
283 // All interesting auvx entry types are below AT_SYSINFO_EHDR
284 #define AT_MAX AT_SYSINFO_EHDR
285 
LinuxDumper(pid_t pid,const char * root_prefix)286 LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix)
287     : pid_(pid),
288       root_prefix_(root_prefix),
289       crash_address_(0),
290       crash_signal_(0),
291       crash_signal_code_(0),
292       crash_thread_(pid),
293       threads_(&allocator_, 8),
294       mappings_(&allocator_),
295       auxv_(&allocator_, AT_MAX + 1) {
296   assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX);
297   // The passed-in size to the constructor (above) is only a hint.
298   // Must call .resize() to do actual initialization of the elements.
299   auxv_.resize(AT_MAX + 1);
300 }
301 
~LinuxDumper()302 LinuxDumper::~LinuxDumper() {
303 }
304 
Init()305 bool LinuxDumper::Init() {
306   return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
307 }
308 
LateInit()309 bool LinuxDumper::LateInit() {
310 #if defined(__ANDROID__)
311   LatePostprocessMappings();
312 #endif
313 
314 #if defined(__CHROMEOS__)
315   CrOSPostProcessMappings(mappings_);
316 #endif
317 
318   return true;
319 }
320 
321 bool
ElfFileIdentifierForMapping(const MappingInfo & mapping,bool member,unsigned int mapping_id,wasteful_vector<uint8_t> & identifier)322 LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
323                                          bool member,
324                                          unsigned int mapping_id,
325                                          wasteful_vector<uint8_t>& identifier) {
326   assert(!member || mapping_id < mappings_.size());
327   if (IsMappedFileOpenUnsafe(mapping))
328     return false;
329 
330   // Special-case linux-gate because it's not a real file.
331   if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) {
332     void* linux_gate = NULL;
333     if (pid_ == sys_getpid()) {
334       linux_gate = reinterpret_cast<void*>(mapping.start_addr);
335     } else {
336       linux_gate = allocator_.Alloc(mapping.size);
337       CopyFromProcess(linux_gate, pid_,
338                       reinterpret_cast<const void*>(mapping.start_addr),
339                       mapping.size);
340     }
341     return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
342   }
343 
344   char filename[PATH_MAX];
345   if (!GetMappingAbsolutePath(mapping, filename))
346     return false;
347   bool filename_modified = HandleDeletedFileInMapping(filename);
348 
349   MemoryMappedFile mapped_file(filename, 0);
350   if (!mapped_file.data() || mapped_file.size() < SELFMAG)
351     return false;
352 
353   bool success =
354       FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
355   if (success && member && filename_modified) {
356     mappings_[mapping_id]->name[my_strlen(mapping.name) -
357                                 sizeof(kDeletedSuffix) + 1] = '\0';
358   }
359 
360   return success;
361 }
362 
SetCrashInfoFromSigInfo(const siginfo_t & siginfo)363 void LinuxDumper::SetCrashInfoFromSigInfo(const siginfo_t& siginfo) {
364   set_crash_address(reinterpret_cast<uintptr_t>(siginfo.si_addr));
365   set_crash_signal(siginfo.si_signo);
366   set_crash_signal_code(siginfo.si_code);
367 }
368 
GetCrashSignalString() const369 const char* LinuxDumper::GetCrashSignalString() const {
370   switch (static_cast<unsigned int>(crash_signal_)) {
371     case MD_EXCEPTION_CODE_LIN_SIGHUP:
372       return "SIGHUP";
373     case MD_EXCEPTION_CODE_LIN_SIGINT:
374       return "SIGINT";
375     case MD_EXCEPTION_CODE_LIN_SIGQUIT:
376       return "SIGQUIT";
377     case MD_EXCEPTION_CODE_LIN_SIGILL:
378       return "SIGILL";
379     case MD_EXCEPTION_CODE_LIN_SIGTRAP:
380       return "SIGTRAP";
381     case MD_EXCEPTION_CODE_LIN_SIGABRT:
382       return "SIGABRT";
383     case MD_EXCEPTION_CODE_LIN_SIGBUS:
384       return "SIGBUS";
385     case MD_EXCEPTION_CODE_LIN_SIGFPE:
386       return "SIGFPE";
387     case MD_EXCEPTION_CODE_LIN_SIGKILL:
388       return "SIGKILL";
389     case MD_EXCEPTION_CODE_LIN_SIGUSR1:
390       return "SIGUSR1";
391     case MD_EXCEPTION_CODE_LIN_SIGSEGV:
392       return "SIGSEGV";
393     case MD_EXCEPTION_CODE_LIN_SIGUSR2:
394       return "SIGUSR2";
395     case MD_EXCEPTION_CODE_LIN_SIGPIPE:
396       return "SIGPIPE";
397     case MD_EXCEPTION_CODE_LIN_SIGALRM:
398       return "SIGALRM";
399     case MD_EXCEPTION_CODE_LIN_SIGTERM:
400       return "SIGTERM";
401     case MD_EXCEPTION_CODE_LIN_SIGSTKFLT:
402       return "SIGSTKFLT";
403     case MD_EXCEPTION_CODE_LIN_SIGCHLD:
404       return "SIGCHLD";
405     case MD_EXCEPTION_CODE_LIN_SIGCONT:
406       return "SIGCONT";
407     case MD_EXCEPTION_CODE_LIN_SIGSTOP:
408       return "SIGSTOP";
409     case MD_EXCEPTION_CODE_LIN_SIGTSTP:
410       return "SIGTSTP";
411     case MD_EXCEPTION_CODE_LIN_SIGTTIN:
412       return "SIGTTIN";
413     case MD_EXCEPTION_CODE_LIN_SIGTTOU:
414       return "SIGTTOU";
415     case MD_EXCEPTION_CODE_LIN_SIGURG:
416       return "SIGURG";
417     case MD_EXCEPTION_CODE_LIN_SIGXCPU:
418       return "SIGXCPU";
419     case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
420       return "SIGXFSZ";
421     case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
422       return "SIGVTALRM";
423     case MD_EXCEPTION_CODE_LIN_SIGPROF:
424       return "SIGPROF";
425     case MD_EXCEPTION_CODE_LIN_SIGWINCH:
426       return "SIGWINCH";
427     case MD_EXCEPTION_CODE_LIN_SIGIO:
428       return "SIGIO";
429     case MD_EXCEPTION_CODE_LIN_SIGPWR:
430       return "SIGPWR";
431     case MD_EXCEPTION_CODE_LIN_SIGSYS:
432       return "SIGSYS";
433     case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED:
434       return "DUMP_REQUESTED";
435     default:
436       return "UNKNOWN";
437   }
438 }
439 
GetMappingAbsolutePath(const MappingInfo & mapping,char path[PATH_MAX]) const440 bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping,
441                                          char path[PATH_MAX]) const {
442   return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX &&
443          my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX;
444 }
445 
446 namespace {
447 // Find the shared object name (SONAME) by examining the ELF information
448 // for |mapping|. If the SONAME is found copy it into the passed buffer
449 // |soname| and return true. The size of the buffer is |soname_size|.
450 // The SONAME will be truncated if it is too long to fit in the buffer.
ElfFileSoName(const LinuxDumper & dumper,const MappingInfo & mapping,char * soname,size_t soname_size)451 bool ElfFileSoName(const LinuxDumper& dumper,
452     const MappingInfo& mapping, char* soname, size_t soname_size) {
453   if (IsMappedFileOpenUnsafe(mapping)) {
454     // Not safe
455     return false;
456   }
457 
458   char filename[PATH_MAX];
459   if (!dumper.GetMappingAbsolutePath(mapping, filename))
460     return false;
461 
462   MemoryMappedFile mapped_file(filename, 0);
463   if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
464     // mmap failed
465     return false;
466   }
467 
468   return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
469 }
470 
471 }  // namespace
472 
473 
GetMappingEffectiveNameAndPath(const MappingInfo & mapping,char * file_path,size_t file_path_size,char * file_name,size_t file_name_size)474 void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
475                                                  char* file_path,
476                                                  size_t file_path_size,
477                                                  char* file_name,
478                                                  size_t file_name_size) {
479   my_strlcpy(file_path, mapping.name, file_path_size);
480 
481   // Tools such as minidump_stackwalk use the name of the module to look up
482   // symbols produced by dump_syms. dump_syms will prefer to use a module's
483   // DT_SONAME as the module name, if one exists, and will fall back to the
484   // filesystem name of the module.
485 
486   // Just use the filesystem name if no SONAME is present.
487   if (!ElfFileSoName(*this, mapping, file_name, file_name_size)) {
488     //   file_path := /path/to/libname.so
489     //   file_name := libname.so
490     const char* basename = my_strrchr(file_path, '/');
491     basename = basename == NULL ? file_path : (basename + 1);
492     my_strlcpy(file_name, basename, file_name_size);
493     return;
494   }
495 
496   if (mapping.exec && mapping.offset != 0) {
497     // If an executable is mapped from a non-zero offset, this is likely because
498     // the executable was loaded directly from inside an archive file (e.g., an
499     // apk on Android).
500     // In this case, we append the file_name to the mapped archive path:
501     //   file_name := libname.so
502     //   file_path := /path/to/ARCHIVE.APK/libname.so
503     if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
504       my_strlcat(file_path, "/", file_path_size);
505       my_strlcat(file_path, file_name, file_path_size);
506     }
507   } else {
508     // Otherwise, replace the basename with the SONAME.
509     char* basename = const_cast<char*>(my_strrchr(file_path, '/'));
510     if (basename) {
511       my_strlcpy(basename + 1, file_name,
512                  file_path_size - my_strlen(file_path) +
513                      my_strlen(basename + 1));
514     } else {
515       my_strlcpy(file_path, file_name, file_path_size);
516     }
517   }
518 }
519 
ReadAuxv()520 bool LinuxDumper::ReadAuxv() {
521   char auxv_path[NAME_MAX];
522   if (!BuildProcPath(auxv_path, pid_, "auxv")) {
523     return false;
524   }
525 
526   int fd = sys_open(auxv_path, O_RDONLY, 0);
527   if (fd < 0) {
528     return false;
529   }
530 
531   elf_aux_entry one_aux_entry;
532   bool res = false;
533   while (sys_read(fd,
534                   &one_aux_entry,
535                   sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
536          one_aux_entry.a_type != AT_NULL) {
537     if (one_aux_entry.a_type <= AT_MAX) {
538       auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val;
539       res = true;
540     }
541   }
542   sys_close(fd);
543   return res;
544 }
545 
EnumerateMappings()546 bool LinuxDumper::EnumerateMappings() {
547   char maps_path[NAME_MAX];
548   if (!BuildProcPath(maps_path, pid_, "maps"))
549     return false;
550 
551   // linux_gate_loc is the beginning of the kernel's mapping of
552   // linux-gate.so in the process.  It doesn't actually show up in the
553   // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR
554   // aux vector entry, which gives the information necessary to special
555   // case its entry when creating the list of mappings.
556   // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
557   // information.
558   const void* linux_gate_loc =
559       reinterpret_cast<void*>(auxv_[AT_SYSINFO_EHDR]);
560   // Although the initial executable is usually the first mapping, it's not
561   // guaranteed (see http://crosbug.com/25355); therefore, try to use the
562   // actual entry point to find the mapping.
563   const void* entry_point_loc = reinterpret_cast<void*>(auxv_[AT_ENTRY]);
564 
565   const int fd = sys_open(maps_path, O_RDONLY, 0);
566   if (fd < 0)
567     return false;
568   LineReader* const line_reader = new(allocator_) LineReader(fd);
569 
570   const char* line;
571   unsigned line_len;
572   while (line_reader->GetNextLine(&line, &line_len)) {
573     uintptr_t start_addr, end_addr, offset;
574 
575     const char* i1 = my_read_hex_ptr(&start_addr, line);
576     if (*i1 == '-') {
577       const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
578       if (*i2 == ' ') {
579         bool exec = (*(i2 + 3) == 'x');
580         const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
581         if (*i3 == ' ') {
582           const char* name = NULL;
583           // Only copy name if the name is a valid path name, or if
584           // it's the VDSO image.
585           if (((name = my_strchr(line, '/')) == NULL) &&
586               linux_gate_loc &&
587               reinterpret_cast<void*>(start_addr) == linux_gate_loc) {
588             name = kLinuxGateLibraryName;
589             offset = 0;
590           }
591           // Merge adjacent mappings into one module, assuming they're a single
592           // library mapped by the dynamic linker. Do this only if their name
593           // matches and either they have the same +x protection flag, or if the
594           // previous mapping is not executable and the new one is, to handle
595           // lld's output (see crbug.com/716484).
596           if (name && !mappings_.empty()) {
597             MappingInfo* module = mappings_.back();
598             if ((start_addr == module->start_addr + module->size) &&
599                 (my_strlen(name) == my_strlen(module->name)) &&
600                 (my_strncmp(name, module->name, my_strlen(name)) == 0) &&
601                 ((exec == module->exec) || (!module->exec && exec))) {
602               module->system_mapping_info.end_addr = end_addr;
603               module->size = end_addr - module->start_addr;
604               module->exec |= exec;
605               line_reader->PopLine(line_len);
606               continue;
607             }
608           }
609           MappingInfo* const module = new(allocator_) MappingInfo;
610           mappings_.push_back(module);
611           my_memset(module, 0, sizeof(MappingInfo));
612           module->system_mapping_info.start_addr = start_addr;
613           module->system_mapping_info.end_addr = end_addr;
614           module->start_addr = start_addr;
615           module->size = end_addr - start_addr;
616           module->offset = offset;
617           module->exec = exec;
618           if (name != NULL) {
619             const unsigned l = my_strlen(name);
620             if (l < sizeof(module->name))
621               my_memcpy(module->name, name, l);
622           }
623         }
624       }
625     }
626     line_reader->PopLine(line_len);
627   }
628 
629   if (entry_point_loc) {
630     for (size_t i = 0; i < mappings_.size(); ++i) {
631       MappingInfo* module = mappings_[i];
632 
633       // If this module contains the entry-point, and it's not already the first
634       // one, then we need to make it be first.  This is because the minidump
635       // format assumes the first module is the one that corresponds to the main
636       // executable (as codified in
637       // processor/minidump.cc:MinidumpModuleList::GetMainModule()).
638       if ((entry_point_loc >= reinterpret_cast<void*>(module->start_addr)) &&
639           (entry_point_loc <
640            reinterpret_cast<void*>(module->start_addr + module->size))) {
641         for (size_t j = i; j > 0; j--)
642           mappings_[j] = mappings_[j - 1];
643         mappings_[0] = module;
644         break;
645       }
646     }
647   }
648 
649   sys_close(fd);
650 
651   return !mappings_.empty();
652 }
653 
654 #if defined(__ANDROID__)
655 
GetLoadedElfHeader(uintptr_t start_addr,ElfW (Ehdr)* ehdr)656 bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) {
657   CopyFromProcess(ehdr, pid_,
658                   reinterpret_cast<const void*>(start_addr),
659                   sizeof(*ehdr));
660   return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0;
661 }
662 
ParseLoadedElfProgramHeaders(ElfW (Ehdr)* ehdr,uintptr_t start_addr,uintptr_t * min_vaddr_ptr,uintptr_t * dyn_vaddr_ptr,size_t * dyn_count_ptr)663 void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr,
664                                                uintptr_t start_addr,
665                                                uintptr_t* min_vaddr_ptr,
666                                                uintptr_t* dyn_vaddr_ptr,
667                                                size_t* dyn_count_ptr) {
668   uintptr_t phdr_addr = start_addr + ehdr->e_phoff;
669 
670   const uintptr_t max_addr = UINTPTR_MAX;
671   uintptr_t min_vaddr = max_addr;
672   uintptr_t dyn_vaddr = 0;
673   size_t dyn_count = 0;
674 
675   for (size_t i = 0; i < ehdr->e_phnum; ++i) {
676     ElfW(Phdr) phdr;
677     CopyFromProcess(&phdr, pid_,
678                     reinterpret_cast<const void*>(phdr_addr),
679                     sizeof(phdr));
680     if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) {
681       min_vaddr = phdr.p_vaddr;
682     }
683     if (phdr.p_type == PT_DYNAMIC) {
684       dyn_vaddr = phdr.p_vaddr;
685       dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn));
686     }
687     phdr_addr += sizeof(phdr);
688   }
689 
690   *min_vaddr_ptr = min_vaddr;
691   *dyn_vaddr_ptr = dyn_vaddr;
692   *dyn_count_ptr = dyn_count;
693 }
694 
HasAndroidPackedRelocations(uintptr_t load_bias,uintptr_t dyn_vaddr,size_t dyn_count)695 bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias,
696                                               uintptr_t dyn_vaddr,
697                                               size_t dyn_count) {
698   uintptr_t dyn_addr = load_bias + dyn_vaddr;
699   for (size_t i = 0; i < dyn_count; ++i) {
700     ElfW(Dyn) dyn;
701     CopyFromProcess(&dyn, pid_,
702                     reinterpret_cast<const void*>(dyn_addr),
703                     sizeof(dyn));
704     if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) {
705       return true;
706     }
707     dyn_addr += sizeof(dyn);
708   }
709   return false;
710 }
711 
GetEffectiveLoadBias(ElfW (Ehdr)* ehdr,uintptr_t start_addr)712 uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr,
713                                             uintptr_t start_addr) {
714   uintptr_t min_vaddr = 0;
715   uintptr_t dyn_vaddr = 0;
716   size_t dyn_count = 0;
717   ParseLoadedElfProgramHeaders(ehdr, start_addr,
718                                &min_vaddr, &dyn_vaddr, &dyn_count);
719   // If |min_vaddr| is non-zero and we find Android packed relocation tags,
720   // return the effective load bias.
721   if (min_vaddr != 0) {
722     const uintptr_t load_bias = start_addr - min_vaddr;
723     if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) {
724       return load_bias;
725     }
726   }
727   // Either |min_vaddr| is zero, or it is non-zero but we did not find the
728   // expected Android packed relocations tags.
729   return start_addr;
730 }
731 
LatePostprocessMappings()732 void LinuxDumper::LatePostprocessMappings() {
733   for (size_t i = 0; i < mappings_.size(); ++i) {
734     // Only consider exec mappings that indicate a file path was mapped, and
735     // where the ELF header indicates a mapped shared library.
736     MappingInfo* mapping = mappings_[i];
737     if (!(mapping->exec && mapping->name[0] == '/')) {
738       continue;
739     }
740     ElfW(Ehdr) ehdr;
741     if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) {
742       continue;
743     }
744     if (ehdr.e_type == ET_DYN) {
745       // Compute the effective load bias for this mapped library, and update
746       // the mapping to hold that rather than |start_addr|, at the same time
747       // adjusting |size| to account for the change in |start_addr|. Where
748       // the library does not contain Android packed relocations,
749       // GetEffectiveLoadBias() returns |start_addr| and the mapping entry
750       // is not changed.
751       const uintptr_t load_bias = GetEffectiveLoadBias(&ehdr,
752                                                        mapping->start_addr);
753       mapping->size += mapping->start_addr - load_bias;
754       mapping->start_addr = load_bias;
755     }
756   }
757 }
758 
759 #endif  // __ANDROID__
760 
761 // Get information about the stack, given the stack pointer. We don't try to
762 // walk the stack since we might not have all the information needed to do
763 // unwind. So we just grab, up to, 32k of stack.
GetStackInfo(const void ** stack,size_t * stack_len,uintptr_t int_stack_pointer)764 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
765                                uintptr_t int_stack_pointer) {
766   // Move the stack pointer to the bottom of the page that it's in.
767   const uintptr_t page_size = getpagesize();
768 
769   uint8_t* const stack_pointer =
770       reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
771 
772   // The number of bytes of stack which we try to capture.
773   static const ptrdiff_t kStackToCapture = 32 * 1024;
774 
775   const MappingInfo* mapping = FindMapping(stack_pointer);
776   if (!mapping)
777     return false;
778   const ptrdiff_t offset = stack_pointer -
779       reinterpret_cast<uint8_t*>(mapping->start_addr);
780   const ptrdiff_t distance_to_end =
781       static_cast<ptrdiff_t>(mapping->size) - offset;
782   *stack_len = distance_to_end > kStackToCapture ?
783       kStackToCapture : distance_to_end;
784   *stack = stack_pointer;
785   return true;
786 }
787 
SanitizeStackCopy(uint8_t * stack_copy,size_t stack_len,uintptr_t stack_pointer,uintptr_t sp_offset)788 void LinuxDumper::SanitizeStackCopy(uint8_t* stack_copy, size_t stack_len,
789                                     uintptr_t stack_pointer,
790                                     uintptr_t sp_offset) {
791   // We optimize the search for containing mappings in three ways:
792   // 1) We expect that pointers into the stack mapping will be common, so
793   //    we cache that address range.
794   // 2) The last referenced mapping is a reasonable predictor for the next
795   //    referenced mapping, so we test that first.
796   // 3) We precompute a bitfield based upon bits 32:32-n of the start and
797   //    stop addresses, and use that to short circuit any values that can
798   //    not be pointers. (n=11)
799   const uintptr_t defaced =
800 #if defined(__LP64__)
801       0x0defaced0defaced;
802 #else
803       0x0defaced;
804 #endif
805   // the bitfield length is 2^test_bits long.
806   const unsigned int test_bits = 11;
807   // byte length of the corresponding array.
808   const unsigned int array_size = 1 << (test_bits - 3);
809   const unsigned int array_mask = array_size - 1;
810   // The amount to right shift pointers by. This captures the top bits
811   // on 32 bit architectures. On 64 bit architectures this would be
812   // uninformative so we take the same range of bits.
813   const unsigned int shift = 32 - 11;
814   const MappingInfo* last_hit_mapping = nullptr;
815   const MappingInfo* hit_mapping = nullptr;
816   const MappingInfo* stack_mapping = FindMappingNoBias(stack_pointer);
817   // The magnitude below which integers are considered to be to be
818   // 'small', and not constitute a PII risk. These are included to
819   // avoid eliding useful register values.
820   const ssize_t small_int_magnitude = 4096;
821 
822   char could_hit_mapping[array_size];
823   my_memset(could_hit_mapping, 0, array_size);
824 
825   // Initialize the bitfield such that if the (pointer >> shift)'th
826   // bit, modulo the bitfield size, is not set then there does not
827   // exist a mapping in mappings_ that would contain that pointer.
828   for (size_t i = 0; i < mappings_.size(); ++i) {
829     if (!mappings_[i]->exec) continue;
830     // For each mapping, work out the (unmodulo'ed) range of bits to
831     // set.
832     uintptr_t start = mappings_[i]->start_addr;
833     uintptr_t end = start + mappings_[i]->size;
834     start >>= shift;
835     end >>= shift;
836     for (size_t bit = start; bit <= end; ++bit) {
837       // Set each bit in the range, applying the modulus.
838       could_hit_mapping[(bit >> 3) & array_mask] |= 1 << (bit & 7);
839     }
840   }
841 
842   // Zero memory that is below the current stack pointer.
843   const uintptr_t offset =
844       (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
845   if (offset) {
846     my_memset(stack_copy, 0, offset);
847   }
848 
849   // Apply sanitization to each complete pointer-aligned word in the
850   // stack.
851   uint8_t* sp;
852   for (sp = stack_copy + offset;
853        sp <= stack_copy + stack_len - sizeof(uintptr_t);
854        sp += sizeof(uintptr_t)) {
855     uintptr_t addr;
856     my_memcpy(&addr, sp, sizeof(uintptr_t));
857     if (static_cast<intptr_t>(addr) <= small_int_magnitude &&
858         static_cast<intptr_t>(addr) >= -small_int_magnitude) {
859       continue;
860     }
861     if (stack_mapping && MappingContainsAddress(*stack_mapping, addr)) {
862       continue;
863     }
864     if (last_hit_mapping && MappingContainsAddress(*last_hit_mapping, addr)) {
865       continue;
866     }
867     uintptr_t test = addr >> shift;
868     if (could_hit_mapping[(test >> 3) & array_mask] & (1 << (test & 7)) &&
869         (hit_mapping = FindMappingNoBias(addr)) != nullptr &&
870         hit_mapping->exec) {
871       last_hit_mapping = hit_mapping;
872       continue;
873     }
874     my_memcpy(sp, &defaced, sizeof(uintptr_t));
875   }
876   // Zero any partial word at the top of the stack, if alignment is
877   // such that that is required.
878   if (sp < stack_copy + stack_len) {
879     my_memset(sp, 0, stack_copy + stack_len - sp);
880   }
881 }
882 
StackHasPointerToMapping(const uint8_t * stack_copy,size_t stack_len,uintptr_t sp_offset,const MappingInfo & mapping)883 bool LinuxDumper::StackHasPointerToMapping(const uint8_t* stack_copy,
884                                            size_t stack_len,
885                                            uintptr_t sp_offset,
886                                            const MappingInfo& mapping) {
887   // Loop over all stack words that would have been on the stack in
888   // the target process (i.e. are word aligned, and at addresses >=
889   // the stack pointer).  Regardless of the alignment of |stack_copy|,
890   // the memory starting at |stack_copy| + |offset| represents an
891   // aligned word in the target process.
892   const uintptr_t low_addr = mapping.system_mapping_info.start_addr;
893   const uintptr_t high_addr = mapping.system_mapping_info.end_addr;
894   const uintptr_t offset =
895       (sp_offset + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
896 
897   for (const uint8_t* sp = stack_copy + offset;
898        sp <= stack_copy + stack_len - sizeof(uintptr_t);
899        sp += sizeof(uintptr_t)) {
900     uintptr_t addr;
901     my_memcpy(&addr, sp, sizeof(uintptr_t));
902     if (low_addr <= addr && addr <= high_addr)
903       return true;
904   }
905   return false;
906 }
907 
908 // Find the mapping which the given memory address falls in.
FindMapping(const void * address) const909 const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
910   const uintptr_t addr = (uintptr_t) address;
911 
912   for (size_t i = 0; i < mappings_.size(); ++i) {
913     const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
914     if (addr >= start && addr - start < mappings_[i]->size)
915       return mappings_[i];
916   }
917 
918   return NULL;
919 }
920 
921 // Find the mapping which the given memory address falls in. Uses the
922 // unadjusted mapping address range from the kernel, rather than the
923 // biased range.
FindMappingNoBias(uintptr_t address) const924 const MappingInfo* LinuxDumper::FindMappingNoBias(uintptr_t address) const {
925   for (size_t i = 0; i < mappings_.size(); ++i) {
926     if (address >= mappings_[i]->system_mapping_info.start_addr &&
927         address < mappings_[i]->system_mapping_info.end_addr) {
928       return mappings_[i];
929     }
930   }
931   return NULL;
932 }
933 
HandleDeletedFileInMapping(char * path) const934 bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
935   static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
936 
937   // Check for ' (deleted)' in |path|.
938   // |path| has to be at least as long as "/x (deleted)".
939   const size_t path_len = my_strlen(path);
940   if (path_len < kDeletedSuffixLen + 2)
941     return false;
942   if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
943                  kDeletedSuffixLen) != 0) {
944     return false;
945   }
946 
947   // Check |path| against the /proc/pid/exe 'symlink'.
948   char exe_link[NAME_MAX];
949   if (!BuildProcPath(exe_link, pid_, "exe"))
950     return false;
951   MappingInfo new_mapping = {0};
952   if (!SafeReadLink(exe_link, new_mapping.name))
953     return false;
954   char new_path[PATH_MAX];
955   if (!GetMappingAbsolutePath(new_mapping, new_path))
956     return false;
957   if (my_strcmp(path, new_path) != 0)
958     return false;
959 
960   // Check to see if someone actually named their executable 'foo (deleted)'.
961   struct kernel_stat exe_stat;
962   struct kernel_stat new_path_stat;
963   if (sys_stat(exe_link, &exe_stat) == 0 &&
964       sys_stat(new_path, &new_path_stat) == 0 &&
965       exe_stat.st_dev == new_path_stat.st_dev &&
966       exe_stat.st_ino == new_path_stat.st_ino) {
967     return false;
968   }
969 
970   my_memcpy(path, exe_link, NAME_MAX);
971   return true;
972 }
973 
974 }  // namespace google_breakpad
975