Home | History | Annotate | Download | only in minidump_writer
      1 // Copyright (c) 2010, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // linux_dumper.cc: Implement google_breakpad::LinuxDumper.
     31 // See linux_dumper.h for details.
     32 
     33 // This code deals with the mechanics of getting information about a crashed
     34 // process. Since this code may run in a compromised address space, the same
     35 // rules apply as detailed at the top of minidump_writer.h: no libc calls and
     36 // use the alternative allocator.
     37 
     38 #include "client/linux/minidump_writer/linux_dumper.h"
     39 
     40 #include <assert.h>
     41 #include <elf.h>
     42 #include <fcntl.h>
     43 #include <limits.h>
     44 #include <stddef.h>
     45 #include <string.h>
     46 
     47 #include "client/linux/minidump_writer/line_reader.h"
     48 #include "common/linux/elfutils.h"
     49 #include "common/linux/file_id.h"
     50 #include "common/linux/linux_libc_support.h"
     51 #include "common/linux/memory_mapped_file.h"
     52 #include "common/linux/safe_readlink.h"
     53 #include "third_party/lss/linux_syscall_support.h"
     54 
     55 static const char kMappedFileUnsafePrefix[] = "/dev/";
     56 static const char kDeletedSuffix[] = " (deleted)";
     57 static const char kReservedFlags[] = " ---p";
     58 
     59 inline static bool IsMappedFileOpenUnsafe(
     60     const google_breakpad::MappingInfo& mapping) {
     61   // It is unsafe to attempt to open a mapped file that lives under /dev,
     62   // because the semantics of the open may be driver-specific so we'd risk
     63   // hanging the crash dumper. And a file in /dev/ almost certainly has no
     64   // ELF file identifier anyways.
     65   return my_strncmp(mapping.name,
     66                     kMappedFileUnsafePrefix,
     67                     sizeof(kMappedFileUnsafePrefix) - 1) == 0;
     68 }
     69 
     70 namespace google_breakpad {
     71 
     72 // All interesting auvx entry types are below AT_SYSINFO_EHDR
     73 #define AT_MAX AT_SYSINFO_EHDR
     74 
     75 LinuxDumper::LinuxDumper(pid_t pid)
     76     : pid_(pid),
     77       crash_address_(0),
     78       crash_signal_(0),
     79       crash_thread_(pid),
     80       threads_(&allocator_, 8),
     81       mappings_(&allocator_),
     82       auxv_(&allocator_, AT_MAX + 1) {
     83   // The passed-in size to the constructor (above) is only a hint.
     84   // Must call .resize() to do actual initialization of the elements.
     85   auxv_.resize(AT_MAX + 1);
     86 }
     87 
     88 LinuxDumper::~LinuxDumper() {
     89 }
     90 
     91 bool LinuxDumper::Init() {
     92   return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
     93 }
     94 
     95 bool
     96 LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
     97                                          bool member,
     98                                          unsigned int mapping_id,
     99                                          uint8_t identifier[sizeof(MDGUID)]) {
    100   assert(!member || mapping_id < mappings_.size());
    101   my_memset(identifier, 0, sizeof(MDGUID));
    102   if (IsMappedFileOpenUnsafe(mapping))
    103     return false;
    104 
    105   // Special-case linux-gate because it's not a real file.
    106   if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) {
    107     void* linux_gate = NULL;
    108     if (pid_ == sys_getpid()) {
    109       linux_gate = reinterpret_cast<void*>(mapping.start_addr);
    110     } else {
    111       linux_gate = allocator_.Alloc(mapping.size);
    112       CopyFromProcess(linux_gate, pid_,
    113                       reinterpret_cast<const void*>(mapping.start_addr),
    114                       mapping.size);
    115     }
    116     return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
    117   }
    118 
    119   char filename[NAME_MAX];
    120   size_t filename_len = my_strlen(mapping.name);
    121   if (filename_len >= NAME_MAX) {
    122     assert(false);
    123     return false;
    124   }
    125   my_memcpy(filename, mapping.name, filename_len);
    126   filename[filename_len] = '\0';
    127   bool filename_modified = HandleDeletedFileInMapping(filename);
    128 
    129   MemoryMappedFile mapped_file(filename, mapping.offset);
    130   if (!mapped_file.data() || mapped_file.size() < SELFMAG)
    131     return false;
    132 
    133   bool success =
    134       FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
    135   if (success && member && filename_modified) {
    136     mappings_[mapping_id]->name[filename_len -
    137                                 sizeof(kDeletedSuffix) + 1] = '\0';
    138   }
    139 
    140   return success;
    141 }
    142 
    143 namespace {
    144 bool ElfFileSoNameFromMappedFile(
    145     const void* elf_base, char* soname, size_t soname_size) {
    146   if (!IsValidElf(elf_base)) {
    147     // Not ELF
    148     return false;
    149   }
    150 
    151   const void* segment_start;
    152   size_t segment_size;
    153   int elf_class;
    154   if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC,
    155                       &segment_start, &segment_size, &elf_class)) {
    156     // No dynamic section
    157     return false;
    158   }
    159 
    160   const void* dynstr_start;
    161   size_t dynstr_size;
    162   if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB,
    163                       &dynstr_start, &dynstr_size, &elf_class)) {
    164     // No dynstr section
    165     return false;
    166   }
    167 
    168   const ElfW(Dyn)* dynamic = static_cast<const ElfW(Dyn)*>(segment_start);
    169   size_t dcount = segment_size / sizeof(ElfW(Dyn));
    170   for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
    171     if (dyn->d_tag == DT_SONAME) {
    172       const char* dynstr = static_cast<const char*>(dynstr_start);
    173       if (dyn->d_un.d_val >= dynstr_size) {
    174         // Beyond the end of the dynstr section
    175         return false;
    176       }
    177       const char* str = dynstr + dyn->d_un.d_val;
    178       const size_t maxsize = dynstr_size - dyn->d_un.d_val;
    179       my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
    180       return true;
    181     }
    182   }
    183 
    184   // Did not find SONAME
    185   return false;
    186 }
    187 
    188 // Find the shared object name (SONAME) by examining the ELF information
    189 // for |mapping|. If the SONAME is found copy it into the passed buffer
    190 // |soname| and return true. The size of the buffer is |soname_size|.
    191 // The SONAME will be truncated if it is too long to fit in the buffer.
    192 bool ElfFileSoName(
    193     const MappingInfo& mapping, char* soname, size_t soname_size) {
    194   if (IsMappedFileOpenUnsafe(mapping)) {
    195     // Not safe
    196     return false;
    197   }
    198 
    199   char filename[NAME_MAX];
    200   size_t filename_len = my_strlen(mapping.name);
    201   if (filename_len >= NAME_MAX) {
    202     assert(false);
    203     // name too long
    204     return false;
    205   }
    206 
    207   my_memcpy(filename, mapping.name, filename_len);
    208   filename[filename_len] = '\0';
    209 
    210   MemoryMappedFile mapped_file(filename, mapping.offset);
    211   if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
    212     // mmap failed
    213     return false;
    214   }
    215 
    216   return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
    217 }
    218 
    219 }  // namespace
    220 
    221 
    222 // static
    223 void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
    224                                                  char* file_path,
    225                                                  size_t file_path_size,
    226                                                  char* file_name,
    227                                                  size_t file_name_size) {
    228   my_strlcpy(file_path, mapping.name, file_path_size);
    229 
    230   // If an executable is mapped from a non-zero offset, this is likely because
    231   // the executable was loaded directly from inside an archive file (e.g., an
    232   // apk on Android). We try to find the name of the shared object (SONAME) by
    233   // looking in the file for ELF sections.
    234   bool mapped_from_archive = false;
    235   if (mapping.exec && mapping.offset != 0)
    236     mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size);
    237 
    238   if (mapped_from_archive) {
    239     // Some tools (e.g., stackwalk) extract the basename from the pathname. In
    240     // this case, we append the file_name to the mapped archive path as follows:
    241     //   file_name := libname.so
    242     //   file_path := /path/to/ARCHIVE.APK/libname.so
    243     if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
    244       my_strlcat(file_path, "/", file_path_size);
    245       my_strlcat(file_path, file_name, file_path_size);
    246     }
    247   } else {
    248     // Common case:
    249     //   file_path := /path/to/libname.so
    250     //   file_name := libname.so
    251     const char* basename = my_strrchr(file_path, '/');
    252     basename = basename == NULL ? file_path : (basename + 1);
    253     my_strlcpy(file_name, basename, file_name_size);
    254   }
    255 }
    256 
    257 bool LinuxDumper::ReadAuxv() {
    258   char auxv_path[NAME_MAX];
    259   if (!BuildProcPath(auxv_path, pid_, "auxv")) {
    260     return false;
    261   }
    262 
    263   int fd = sys_open(auxv_path, O_RDONLY, 0);
    264   if (fd < 0) {
    265     return false;
    266   }
    267 
    268   elf_aux_entry one_aux_entry;
    269   bool res = false;
    270   while (sys_read(fd,
    271                   &one_aux_entry,
    272                   sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
    273          one_aux_entry.a_type != AT_NULL) {
    274     if (one_aux_entry.a_type <= AT_MAX) {
    275       auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val;
    276       res = true;
    277     }
    278   }
    279   sys_close(fd);
    280   return res;
    281 }
    282 
    283 bool LinuxDumper::EnumerateMappings() {
    284   char maps_path[NAME_MAX];
    285   if (!BuildProcPath(maps_path, pid_, "maps"))
    286     return false;
    287 
    288   // linux_gate_loc is the beginning of the kernel's mapping of
    289   // linux-gate.so in the process.  It doesn't actually show up in the
    290   // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR
    291   // aux vector entry, which gives the information necessary to special
    292   // case its entry when creating the list of mappings.
    293   // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
    294   // information.
    295   const void* linux_gate_loc =
    296       reinterpret_cast<void *>(auxv_[AT_SYSINFO_EHDR]);
    297   // Although the initial executable is usually the first mapping, it's not
    298   // guaranteed (see http://crosbug.com/25355); therefore, try to use the
    299   // actual entry point to find the mapping.
    300   const void* entry_point_loc = reinterpret_cast<void *>(auxv_[AT_ENTRY]);
    301 
    302   const int fd = sys_open(maps_path, O_RDONLY, 0);
    303   if (fd < 0)
    304     return false;
    305   LineReader* const line_reader = new(allocator_) LineReader(fd);
    306 
    307   const char* line;
    308   unsigned line_len;
    309   while (line_reader->GetNextLine(&line, &line_len)) {
    310     uintptr_t start_addr, end_addr, offset;
    311 
    312     const char* i1 = my_read_hex_ptr(&start_addr, line);
    313     if (*i1 == '-') {
    314       const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
    315       if (*i2 == ' ') {
    316         bool exec = (*(i2 + 3) == 'x');
    317         const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
    318         if (*i3 == ' ') {
    319           const char* name = NULL;
    320           // Only copy name if the name is a valid path name, or if
    321           // it's the VDSO image.
    322           if (((name = my_strchr(line, '/')) == NULL) &&
    323               linux_gate_loc &&
    324               reinterpret_cast<void*>(start_addr) == linux_gate_loc) {
    325             name = kLinuxGateLibraryName;
    326             offset = 0;
    327           }
    328           // Merge adjacent mappings with the same name into one module,
    329           // assuming they're a single library mapped by the dynamic linker
    330           if (name && !mappings_.empty()) {
    331             MappingInfo* module = mappings_.back();
    332             if ((start_addr == module->start_addr + module->size) &&
    333                 (my_strlen(name) == my_strlen(module->name)) &&
    334                 (my_strncmp(name, module->name, my_strlen(name)) == 0)) {
    335               module->size = end_addr - module->start_addr;
    336               line_reader->PopLine(line_len);
    337               continue;
    338             }
    339           }
    340           // Also merge mappings that result from address ranges that the
    341           // linker reserved but which a loaded library did not use. These
    342           // appear as an anonymous private mapping with no access flags set
    343           // and which directly follow an executable mapping.
    344           if (!name && !mappings_.empty()) {
    345             MappingInfo* module = mappings_.back();
    346             if ((start_addr == module->start_addr + module->size) &&
    347                 module->exec &&
    348                 module->name[0] == '/' &&
    349                 offset == 0 && my_strncmp(i2,
    350                                           kReservedFlags,
    351                                           sizeof(kReservedFlags) - 1) == 0) {
    352               module->size = end_addr - module->start_addr;
    353               line_reader->PopLine(line_len);
    354               continue;
    355             }
    356           }
    357           MappingInfo* const module = new(allocator_) MappingInfo;
    358           my_memset(module, 0, sizeof(MappingInfo));
    359           module->start_addr = start_addr;
    360           module->size = end_addr - start_addr;
    361           module->offset = offset;
    362           module->exec = exec;
    363           if (name != NULL) {
    364             const unsigned l = my_strlen(name);
    365             if (l < sizeof(module->name))
    366               my_memcpy(module->name, name, l);
    367           }
    368           // If this is the entry-point mapping, and it's not already the
    369           // first one, then we need to make it be first.  This is because
    370           // the minidump format assumes the first module is the one that
    371           // corresponds to the main executable (as codified in
    372           // processor/minidump.cc:MinidumpModuleList::GetMainModule()).
    373           if (entry_point_loc &&
    374               (entry_point_loc >=
    375                   reinterpret_cast<void*>(module->start_addr)) &&
    376               (entry_point_loc <
    377                   reinterpret_cast<void*>(module->start_addr+module->size)) &&
    378               !mappings_.empty()) {
    379             // push the module onto the front of the list.
    380             mappings_.resize(mappings_.size() + 1);
    381             for (size_t idx = mappings_.size() - 1; idx > 0; idx--)
    382               mappings_[idx] = mappings_[idx - 1];
    383             mappings_[0] = module;
    384           } else {
    385             mappings_.push_back(module);
    386           }
    387         }
    388       }
    389     }
    390     line_reader->PopLine(line_len);
    391   }
    392 
    393   sys_close(fd);
    394 
    395   return !mappings_.empty();
    396 }
    397 
    398 // Get information about the stack, given the stack pointer. We don't try to
    399 // walk the stack since we might not have all the information needed to do
    400 // unwind. So we just grab, up to, 32k of stack.
    401 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
    402                                uintptr_t int_stack_pointer) {
    403   // Move the stack pointer to the bottom of the page that it's in.
    404   const uintptr_t page_size = getpagesize();
    405 
    406   uint8_t* const stack_pointer =
    407       reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
    408 
    409   // The number of bytes of stack which we try to capture.
    410   static const ptrdiff_t kStackToCapture = 32 * 1024;
    411 
    412   const MappingInfo* mapping = FindMapping(stack_pointer);
    413   if (!mapping)
    414     return false;
    415   const ptrdiff_t offset = stack_pointer -
    416       reinterpret_cast<uint8_t*>(mapping->start_addr);
    417   const ptrdiff_t distance_to_end =
    418       static_cast<ptrdiff_t>(mapping->size) - offset;
    419   *stack_len = distance_to_end > kStackToCapture ?
    420       kStackToCapture : distance_to_end;
    421   *stack = stack_pointer;
    422   return true;
    423 }
    424 
    425 // Find the mapping which the given memory address falls in.
    426 const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
    427   const uintptr_t addr = (uintptr_t) address;
    428 
    429   for (size_t i = 0; i < mappings_.size(); ++i) {
    430     const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
    431     if (addr >= start && addr - start < mappings_[i]->size)
    432       return mappings_[i];
    433   }
    434 
    435   return NULL;
    436 }
    437 
    438 bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
    439   static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
    440 
    441   // Check for ' (deleted)' in |path|.
    442   // |path| has to be at least as long as "/x (deleted)".
    443   const size_t path_len = my_strlen(path);
    444   if (path_len < kDeletedSuffixLen + 2)
    445     return false;
    446   if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
    447                  kDeletedSuffixLen) != 0) {
    448     return false;
    449   }
    450 
    451   // Check |path| against the /proc/pid/exe 'symlink'.
    452   char exe_link[NAME_MAX];
    453   char new_path[NAME_MAX];
    454   if (!BuildProcPath(exe_link, pid_, "exe"))
    455     return false;
    456   if (!SafeReadLink(exe_link, new_path))
    457     return false;
    458   if (my_strcmp(path, new_path) != 0)
    459     return false;
    460 
    461   // Check to see if someone actually named their executable 'foo (deleted)'.
    462   struct kernel_stat exe_stat;
    463   struct kernel_stat new_path_stat;
    464   if (sys_stat(exe_link, &exe_stat) == 0 &&
    465       sys_stat(new_path, &new_path_stat) == 0 &&
    466       exe_stat.st_dev == new_path_stat.st_dev &&
    467       exe_stat.st_ino == new_path_stat.st_ino) {
    468     return false;
    469   }
    470 
    471   my_memcpy(path, exe_link, NAME_MAX);
    472   return true;
    473 }
    474 
    475 }  // namespace google_breakpad
    476