tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

shared-libraries-macos.cc (6723B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "mozilla/SharedLibraries.h"
      7 
      8 #include "platform.h"
      9 
     10 #include <AvailabilityMacros.h>
     11 
     12 #include <dlfcn.h>
     13 #include <mach-o/arch.h>
     14 #include <mach-o/dyld_images.h>
     15 #include <mach-o/dyld.h>
     16 #include <mach-o/loader.h>
     17 #include <mach/mach_init.h>
     18 #include <mach/mach_traps.h>
     19 #include <mach/task_info.h>
     20 #include <mach/task.h>
     21 #include <sstream>
     22 #include <string.h>
     23 #include <vector>
     24 
     25 // Architecture specific abstraction.
     26 #if defined(GP_ARCH_x86)
     27 typedef mach_header platform_mach_header;
     28 typedef segment_command mach_segment_command_type;
     29 #  define MACHO_MAGIC_NUMBER MH_MAGIC
     30 #  define CMD_SEGMENT LC_SEGMENT
     31 #  define seg_size uint32_t
     32 #else
     33 typedef mach_header_64 platform_mach_header;
     34 typedef segment_command_64 mach_segment_command_type;
     35 #  define MACHO_MAGIC_NUMBER MH_MAGIC_64
     36 #  define CMD_SEGMENT LC_SEGMENT_64
     37 #  define seg_size uint64_t
     38 #endif
     39 
     40 struct NativeSharedLibrary {
     41  const platform_mach_header* header;
     42  std::string path;
     43 };
     44 static std::vector<NativeSharedLibrary>* sSharedLibrariesList = nullptr;
     45 
     46 class MOZ_RAII SharedLibrariesLock {
     47 public:
     48  SharedLibrariesLock() { sSharedLibrariesMutex.Lock(); }
     49 
     50  ~SharedLibrariesLock() { sSharedLibrariesMutex.Unlock(); }
     51 
     52  SharedLibrariesLock(const SharedLibrariesLock&) = delete;
     53  void operator=(const SharedLibrariesLock&) = delete;
     54 
     55 private:
     56  static mozilla::baseprofiler::detail::BaseProfilerMutex sSharedLibrariesMutex;
     57 };
     58 
     59 MOZ_RUNINIT mozilla::baseprofiler::detail::BaseProfilerMutex
     60    SharedLibrariesLock::sSharedLibrariesMutex;
     61 
     62 static void SharedLibraryAddImage(const struct mach_header* mh,
     63                                  intptr_t vmaddr_slide) {
     64  // NOTE: Presumably for backwards-compatibility reasons, this function accepts
     65  // a mach_header even on 64-bit where it ought to be a mach_header_64. We cast
     66  // it to the right type here.
     67  auto header = reinterpret_cast<const platform_mach_header*>(mh);
     68 
     69  Dl_info info;
     70  if (!dladdr(header, &info)) {
     71    return;
     72  }
     73 
     74  SharedLibrariesLock lock;
     75  if (!sSharedLibrariesList) {
     76    return;
     77  }
     78 
     79  NativeSharedLibrary lib = {header, info.dli_fname};
     80  sSharedLibrariesList->push_back(lib);
     81 }
     82 
     83 static void SharedLibraryRemoveImage(const struct mach_header* mh,
     84                                     intptr_t vmaddr_slide) {
     85  // NOTE: Presumably for backwards-compatibility reasons, this function accepts
     86  // a mach_header even on 64-bit where it ought to be a mach_header_64. We cast
     87  // it to the right type here.
     88  auto header = reinterpret_cast<const platform_mach_header*>(mh);
     89 
     90  SharedLibrariesLock lock;
     91  if (!sSharedLibrariesList) {
     92    return;
     93  }
     94 
     95  uint32_t count = sSharedLibrariesList->size();
     96  for (uint32_t i = 0; i < count; ++i) {
     97    if ((*sSharedLibrariesList)[i].header == header) {
     98      sSharedLibrariesList->erase(sSharedLibrariesList->begin() + i);
     99      return;
    100    }
    101  }
    102 }
    103 
    104 void SharedLibraryInfo::Initialize() {
    105  // NOTE: We intentionally leak this memory here. We're allocating dynamically
    106  // in order to avoid static initializers.
    107  sSharedLibrariesList = new std::vector<NativeSharedLibrary>();
    108 
    109  _dyld_register_func_for_add_image(SharedLibraryAddImage);
    110  _dyld_register_func_for_remove_image(SharedLibraryRemoveImage);
    111 }
    112 
    113 static void addSharedLibrary(const platform_mach_header* header,
    114                             const char* path, SharedLibraryInfo& info) {
    115  const struct load_command* cmd =
    116      reinterpret_cast<const struct load_command*>(header + 1);
    117 
    118  seg_size size = 0;
    119  unsigned long long start = reinterpret_cast<unsigned long long>(header);
    120  // Find the cmd segment in the macho image. It will contain the offset we care
    121  // about.
    122  const uint8_t* uuid_bytes = nullptr;
    123  for (unsigned int i = 0;
    124       cmd && (i < header->ncmds) && (uuid_bytes == nullptr || size == 0);
    125       ++i) {
    126    if (cmd->cmd == CMD_SEGMENT) {
    127      const mach_segment_command_type* seg =
    128          reinterpret_cast<const mach_segment_command_type*>(cmd);
    129 
    130      if (!strcmp(seg->segname, "__TEXT")) {
    131        size = seg->vmsize;
    132      }
    133    } else if (cmd->cmd == LC_UUID) {
    134      const uuid_command* ucmd = reinterpret_cast<const uuid_command*>(cmd);
    135      uuid_bytes = ucmd->uuid;
    136    }
    137 
    138    cmd = reinterpret_cast<const struct load_command*>(
    139        reinterpret_cast<const char*>(cmd) + cmd->cmdsize);
    140  }
    141 
    142  std::string uuid;
    143  std::string breakpadId;
    144  if (uuid_bytes != nullptr) {
    145    static constexpr char digits[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
    146                                        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    147    for (int i = 0; i < 16; ++i) {
    148      uint8_t byte = uuid_bytes[i];
    149      uuid += digits[byte >> 4];
    150      uuid += digits[byte & 0xFu];
    151    }
    152 
    153    // Breakpad id is the same as the uuid but with the additional trailing 0
    154    // for the breakpad id age.
    155    breakpadId = uuid;
    156    // breakpad id age.
    157    breakpadId += '0';
    158  }
    159 
    160  std::string pathStr = path;
    161 
    162  size_t pos = pathStr.rfind('/');
    163  std::string nameStr =
    164      (pos != std::string::npos) ? pathStr.substr(pos + 1) : pathStr;
    165 
    166  const NXArchInfo* archInfo =
    167      NXGetArchInfoFromCpuType(header->cputype, header->cpusubtype);
    168 
    169  info.AddSharedLibrary(SharedLibrary(
    170      start, start + size, 0, breakpadId, uuid, nameStr, pathStr, nameStr,
    171      pathStr, std::string{}, archInfo ? archInfo->name : ""));
    172 }
    173 
    174 // Translate the statically stored sSharedLibrariesList information into a
    175 // SharedLibraryInfo object.
    176 SharedLibraryInfo SharedLibraryInfo::GetInfoForSelf() {
    177  SharedLibrariesLock lock;
    178  SharedLibraryInfo sharedLibraryInfo;
    179 
    180  for (auto& info : *sSharedLibrariesList) {
    181    addSharedLibrary(info.header, info.path.c_str(), sharedLibraryInfo);
    182  }
    183 
    184  // Add the entry for dyld itself.
    185  // We only support macOS 10.12+, which corresponds to dyld version 15+.
    186  // dyld version 15 added the dyldPath property.
    187  task_dyld_info_data_t task_dyld_info;
    188  mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
    189  if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&task_dyld_info,
    190                &count) != KERN_SUCCESS) {
    191    return sharedLibraryInfo;
    192  }
    193 
    194  struct dyld_all_image_infos* aii =
    195      (struct dyld_all_image_infos*)task_dyld_info.all_image_info_addr;
    196  if (aii->version >= 15) {
    197    const platform_mach_header* header =
    198        reinterpret_cast<const platform_mach_header*>(
    199            aii->dyldImageLoadAddress);
    200    addSharedLibrary(header, aii->dyldPath, sharedLibraryInfo);
    201  }
    202 
    203  return sharedLibraryInfo;
    204 }