tor-browser

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

ElfLoader.h (16342B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifndef ElfLoader_h
      6 #define ElfLoader_h
      7 
      8 #include <vector>
      9 #include <dlfcn.h>
     10 #include <signal.h>
     11 #include "mozilla/Atomics.h"
     12 #include "mozilla/RefCounted.h"
     13 #include "mozilla/RefPtr.h"
     14 #include "Elfxx.h"
     15 #include "Mappable.h"
     16 
     17 /**
     18 * dlfcn.h replacement functions
     19 */
     20 extern "C" {
     21 void* __wrap_dlopen(const char* path, int flags);
     22 const char* __wrap_dlerror(void);
     23 void* __wrap_dlsym(void* handle, const char* symbol);
     24 int __wrap_dlclose(void* handle);
     25 
     26 #ifndef HAVE_DLADDR
     27 typedef struct {
     28  const char* dli_fname;
     29  void* dli_fbase;
     30  const char* dli_sname;
     31  void* dli_saddr;
     32 } Dl_info;
     33 #endif
     34 int __wrap_dladdr(const void* addr, Dl_info* info);
     35 
     36 typedef int (*dl_phdr_cb)(struct dl_phdr_info*, size_t, void*);
     37 int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void* data);
     38 
     39 #ifdef __ARM_EABI__
     40 const void* __wrap___gnu_Unwind_Find_exidx(void* pc, int* pcount);
     41 #endif
     42 }
     43 
     44 /* Forward declarations for use in LibHandle */
     45 class BaseElf;
     46 class CustomElf;
     47 class SystemElf;
     48 
     49 /**
     50 * Specialize RefCounted template for LibHandle. We may get references to
     51 * LibHandles during the execution of their destructor, so we need
     52 * RefCounted<LibHandle>::Release to support some reentrancy. See further
     53 * below.
     54 */
     55 class LibHandle;
     56 
     57 namespace mozilla {
     58 namespace detail {
     59 
     60 template <>
     61 inline void RefCounted<LibHandle, AtomicRefCount>::Release() const;
     62 
     63 #ifdef DEBUG
     64 template <>
     65 inline RefCounted<LibHandle, AtomicRefCount>::~RefCounted() {
     66  MOZ_ASSERT(mRefCnt == 0x7fffdead);
     67 }
     68 #endif
     69 
     70 } /* namespace detail */
     71 } /* namespace mozilla */
     72 
     73 /**
     74 * Abstract class for loaded libraries. Libraries may be loaded through the
     75 * system linker or this linker, both cases will be derived from this class.
     76 */
     77 class LibHandle : public mozilla::external::AtomicRefCounted<LibHandle> {
     78 public:
     79  MOZ_DECLARE_REFCOUNTED_TYPENAME(LibHandle)
     80  /**
     81   * Constructor. Takes the path of the loaded library and will store a copy
     82   * of the leaf name.
     83   */
     84  LibHandle(const char* path)
     85      : directRefCnt(0),
     86        path(path ? strdup(path) : nullptr),
     87        mappable(nullptr) {}
     88 
     89  /**
     90   * Destructor.
     91   */
     92  virtual ~LibHandle();
     93 
     94  /**
     95   * Returns the pointer to the address to which the given symbol resolves
     96   * inside the library. It is not supposed to resolve the symbol in other
     97   * libraries, although in practice, it will for system libraries.
     98   */
     99  virtual void* GetSymbolPtr(const char* symbol) const = 0;
    100 
    101  /**
    102   * Returns whether the given address is part of the virtual address space
    103   * covered by the loaded library.
    104   */
    105  virtual bool Contains(void* addr) const = 0;
    106 
    107  /**
    108   * Returns the base address of the loaded library.
    109   */
    110  virtual void* GetBase() const = 0;
    111 
    112  /**
    113   * Returns the file name of the library without the containing directory.
    114   */
    115  const char* GetName() const;
    116 
    117  /**
    118   * Returns the full path of the library, when available. Otherwise, returns
    119   * the file name.
    120   */
    121  const char* GetPath() const { return path; }
    122 
    123  /**
    124   * Library handles can be referenced from other library handles or
    125   * externally (when dlopen()ing using this linker). We need to be
    126   * able to distinguish between the two kind of referencing for better
    127   * bookkeeping.
    128   */
    129  void AddDirectRef() {
    130    mozilla::external::AtomicRefCounted<LibHandle>::AddRef();
    131    ++directRefCnt;
    132  }
    133 
    134  /**
    135   * Releases a direct reference, and returns whether there are any direct
    136   * references left.
    137   */
    138  bool ReleaseDirectRef() {
    139    const MozRefCountType count = --directRefCnt;
    140    MOZ_ASSERT(count + 1 > 0);
    141    MOZ_ASSERT(count + 1 <=
    142               mozilla::external::AtomicRefCounted<LibHandle>::refCount());
    143    mozilla::external::AtomicRefCounted<LibHandle>::Release();
    144    return !!count;
    145  }
    146 
    147  /**
    148   * Returns the number of direct references
    149   */
    150  MozRefCountType DirectRefCount() { return directRefCnt; }
    151 
    152 #ifdef __ARM_EABI__
    153  /**
    154   * Find the address and entry count of the ARM.exidx section
    155   * associated with the library
    156   */
    157  virtual const void* FindExidx(int* pcount) const = 0;
    158 #endif
    159 
    160 protected:
    161  /**
    162   * Returns the instance, casted as the wanted type. Returns nullptr if
    163   * that's not the actual type. (short of a better way to do this without
    164   * RTTI)
    165   */
    166  friend class ElfLoader;
    167  friend class CustomElf;
    168  friend class SEGVHandler;
    169  friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void* data);
    170  virtual BaseElf* AsBaseElf() { return nullptr; }
    171  virtual SystemElf* AsSystemElf() { return nullptr; }
    172 
    173 private:
    174  mozilla::Atomic<MozRefCountType> directRefCnt;
    175  char* path;
    176 
    177  /* Mappable object keeping the result of GetMappable() */
    178  mutable RefPtr<Mappable> mappable;
    179 };
    180 
    181 /**
    182 * Specialized RefCounted<LibHandle>::Release. Under normal operation, when
    183 * mRefCnt reaches 0, the LibHandle is deleted. Its mRefCnt is however
    184 * increased to 1 on normal builds, and 0x7fffdead on debug builds so that the
    185 * LibHandle can still be referenced while the destructor is executing. The
    186 * mRefCnt is allowed to grow > 0x7fffdead, but not to decrease under that
    187 * value, which would mean too many Releases from within the destructor.
    188 */
    189 namespace mozilla {
    190 namespace detail {
    191 
    192 template <>
    193 inline void RefCounted<LibHandle, AtomicRefCount>::Release() const {
    194 #ifdef DEBUG
    195  if (mRefCnt > 0x7fff0000) MOZ_ASSERT(mRefCnt > 0x7fffdead);
    196 #endif
    197  MOZ_ASSERT(mRefCnt > 0);
    198  if (mRefCnt > 0) {
    199    if (0 == --mRefCnt) {
    200 #ifdef DEBUG
    201      mRefCnt = 0x7fffdead;
    202 #else
    203      ++mRefCnt;
    204 #endif
    205      delete static_cast<const LibHandle*>(this);
    206    }
    207  }
    208 }
    209 
    210 } /* namespace detail */
    211 } /* namespace mozilla */
    212 
    213 /**
    214 * Class handling libraries loaded by the system linker
    215 */
    216 class SystemElf : public LibHandle {
    217 public:
    218  /**
    219   * Returns a new SystemElf for the given path. The given flags are passed
    220   * to dlopen().
    221   */
    222  static already_AddRefed<LibHandle> Load(const char* path, int flags);
    223 
    224  /**
    225   * Inherited from LibHandle
    226   */
    227  virtual ~SystemElf();
    228  virtual void* GetSymbolPtr(const char* symbol) const;
    229  virtual bool Contains(void* addr) const { return false; /* UNIMPLEMENTED */ }
    230  virtual void* GetBase() const { return nullptr; /* UNIMPLEMENTED */ }
    231 
    232 #ifdef __ARM_EABI__
    233  virtual const void* FindExidx(int* pcount) const;
    234 #endif
    235 
    236 protected:
    237  /**
    238   * Returns the instance, casted as SystemElf. (short of a better way to do
    239   * this without RTTI)
    240   */
    241  friend class ElfLoader;
    242  virtual SystemElf* AsSystemElf() { return this; }
    243 
    244  /**
    245   * Remove the reference to the system linker handle. This avoids dlclose()
    246   * being called when the instance is destroyed.
    247   */
    248  void Forget() { dlhandle = nullptr; }
    249 
    250 private:
    251  /**
    252   * Private constructor
    253   */
    254  SystemElf(const char* path, void* handle)
    255      : LibHandle(path), dlhandle(handle) {}
    256 
    257  /* Handle as returned by system dlopen() */
    258  void* dlhandle;
    259 };
    260 
    261 /**
    262 * The ElfLoader registers its own SIGSEGV handler to handle segmentation
    263 * faults within the address space of the loaded libraries. It however
    264 * allows a handler to be set for faults in other places, and redispatches
    265 * to the handler set through signal() or sigaction().
    266 */
    267 class SEGVHandler {
    268 public:
    269  bool hasRegisteredHandler() {
    270    if (!initialized) FinishInitialization();
    271    return registeredHandler;
    272  }
    273 
    274  static int __wrap_sigaction(int signum, const struct sigaction* act,
    275                              struct sigaction* oldact);
    276 
    277 protected:
    278  SEGVHandler();
    279  ~SEGVHandler();
    280 
    281 private:
    282  /**
    283   * The constructor doesn't do all initialization, and the tail is done
    284   * at a later time.
    285   */
    286  void FinishInitialization();
    287 
    288  /**
    289   * SIGSEGV handler registered with __wrap_signal or __wrap_sigaction.
    290   */
    291  struct sigaction action;
    292 
    293  /**
    294   * ElfLoader SIGSEGV handler.
    295   */
    296  static void handler(int signum, siginfo_t* info, void* context);
    297 
    298  /**
    299   * Temporary test handler.
    300   */
    301  static void test_handler(int signum, siginfo_t* info, void* context);
    302 
    303  /**
    304   * Size of the alternative stack. The printf family requires more than 8KB
    305   * of stack, and our signal handler may print a few things.
    306   */
    307  static const size_t stackSize = 12 * 1024;
    308 
    309  /**
    310   * Alternative stack information used before initialization.
    311   */
    312  stack_t oldStack;
    313 
    314  /**
    315   * Pointer to an alternative stack for signals. Only set if oldStack is
    316   * not set or not big enough.
    317   */
    318  MappedPtr stackPtr;
    319 
    320  bool initialized;
    321  bool registeredHandler;
    322  bool signalHandlingSlow;
    323 };
    324 
    325 /**
    326 * Elf Loader class in charge of loading and bookkeeping libraries.
    327 */
    328 class ElfLoader : public SEGVHandler {
    329 public:
    330  /**
    331   * The Elf Loader instance
    332   */
    333  static ElfLoader Singleton;
    334 
    335  /**
    336   * Loads the given library with the given flags. Equivalent to dlopen()
    337   * The extra "parent" argument optionally gives the handle of the library
    338   * requesting the given library to be loaded. The loader may look in the
    339   * directory containing that parent library for the library to load.
    340   */
    341  already_AddRefed<LibHandle> Load(const char* path, int flags,
    342                                   LibHandle* parent = nullptr);
    343 
    344  /**
    345   * Returns the handle of the library containing the given address in
    346   * its virtual address space, i.e. the library handle for which
    347   * LibHandle::Contains returns true. Its purpose is to allow to
    348   * implement dladdr().
    349   */
    350  already_AddRefed<LibHandle> GetHandleByPtr(void* addr);
    351 
    352  /**
    353   * Returns a Mappable object for the path. Paths in the form
    354   *   /foo/bar/baz/archive!/directory/lib.so
    355   * try to load the directory/lib.so in /foo/bar/baz/archive, provided
    356   * that file is a Zip archive.
    357   */
    358  static Mappable* GetMappableFromPath(const char* path);
    359 
    360  void ExpectShutdown(bool val) { expect_shutdown = val; }
    361  bool IsShutdownExpected() { return expect_shutdown; }
    362 
    363 private:
    364  bool expect_shutdown;
    365 
    366 protected:
    367  /**
    368   * Registers the given handle. This method is meant to be called by
    369   * LibHandle subclass creators.
    370   */
    371  void Register(LibHandle* handle);
    372  void Register(CustomElf* handle);
    373 
    374  /**
    375   * Forget about the given handle. This method is meant to be called by
    376   * LibHandle subclass destructors.
    377   */
    378  void Forget(LibHandle* handle);
    379  void Forget(CustomElf* handle);
    380 
    381  friend class SystemElf;
    382  friend const char* __wrap_dlerror(void);
    383  friend void* __wrap_dlsym(void* handle, const char* symbol);
    384  friend int __wrap_dlclose(void* handle);
    385  /* __wrap_dlerror() returns this custom last error if non-null or the system
    386   * dlerror() value if this is null. Must refer to a string constant. */
    387  mozilla::Atomic<const char*, mozilla::Relaxed> lastError;
    388 
    389 private:
    390  ElfLoader() : expect_shutdown(true), lastError(nullptr) {
    391    pthread_mutex_init(&handlesMutex, nullptr);
    392  }
    393 
    394  ~ElfLoader();
    395 
    396  /* Initialization code that can't run during static initialization. */
    397  void Init();
    398 
    399  /* System loader handle for the library/program containing our code. This
    400   * is used to resolve wrapped functions. */
    401  RefPtr<LibHandle> self_elf;
    402 
    403  /* Bookkeeping */
    404  typedef std::vector<LibHandle*> LibHandleList;
    405  LibHandleList handles;
    406 
    407  pthread_mutex_t handlesMutex;
    408 
    409 protected:
    410  friend class CustomElf;
    411  friend class LoadedElf;
    412 
    413  /* Definition of static destructors as to be used for C++ ABI compatibility */
    414  typedef void (*Destructor)(void* object);
    415 
    416  /**
    417   * C++ ABI makes static initializers register destructors through a specific
    418   * atexit interface. On glibc/linux systems, the dso_handle is a pointer
    419   * within a given library. On bionic/android systems, it is an undefined
    420   * symbol. Making sense of the value is not really important, and all that
    421   * is really important is that it is different for each loaded library, so
    422   * that they can be discriminated when shutting down. For convenience, on
    423   * systems where the dso handle is a symbol, that symbol is resolved to
    424   * point at corresponding CustomElf.
    425   *
    426   * Destructors are registered with __*_atexit with an associated object to
    427   * be passed as argument when it is called.
    428   *
    429   * When __cxa_finalize is called, destructors registered for the given
    430   * DSO handle are called in the reverse order they were registered.
    431   */
    432 #ifdef __ARM_EABI__
    433  static int __wrap_aeabi_atexit(void* that, Destructor destructor,
    434                                 void* dso_handle);
    435 #else
    436  static int __wrap_cxa_atexit(Destructor destructor, void* that,
    437                               void* dso_handle);
    438 #endif
    439 
    440  static void __wrap_cxa_finalize(void* dso_handle);
    441 
    442  /**
    443   * Registered destructor. Keeps track of the destructor function pointer,
    444   * associated object to call it with, and DSO handle.
    445   */
    446  class DestructorCaller {
    447   public:
    448    DestructorCaller(Destructor destructor, void* object, void* dso_handle)
    449        : destructor(destructor), object(object), dso_handle(dso_handle) {}
    450 
    451    /**
    452     * Call the destructor function with the associated object.
    453     * Call only once, see CustomElf::~CustomElf.
    454     */
    455    void Call();
    456 
    457    /**
    458     * Returns whether the destructor is associated to the given DSO handle
    459     */
    460    bool IsForHandle(void* handle) const { return handle == dso_handle; }
    461 
    462   private:
    463    Destructor destructor;
    464    void* object;
    465    void* dso_handle;
    466  };
    467 
    468 private:
    469  /* Keep track of all registered destructors */
    470  std::vector<DestructorCaller> destructors;
    471 
    472  /* Forward declaration, see further below */
    473  class DebuggerHelper;
    474 
    475 public:
    476  /* Loaded object descriptor for the debugger interface below*/
    477  struct link_map {
    478    /* Base address of the loaded object. */
    479    const void* l_addr;
    480    /* File name */
    481    const char* l_name;
    482    /* Address of the PT_DYNAMIC segment. */
    483    const void* l_ld;
    484 
    485   private:
    486    friend class ElfLoader::DebuggerHelper;
    487    /* Double linked list of loaded objects. */
    488    link_map *l_next, *l_prev;
    489  };
    490 
    491 private:
    492  /* Data structure used by the linker to give details about shared objects it
    493   * loaded to debuggers. This is normally defined in link.h, but Android
    494   * headers lack this file. */
    495  struct r_debug {
    496    /* Version number of the protocol. */
    497    int r_version;
    498 
    499    /* Head of the linked list of loaded objects. */
    500    link_map* r_map;
    501 
    502    /* Function to be called when updates to the linked list of loaded objects
    503     * are going to occur. The function is to be called before and after
    504     * changes. */
    505    void (*r_brk)(void);
    506 
    507    /* Indicates to the debugger what state the linked list of loaded objects
    508     * is in when the function above is called. */
    509    enum {
    510      RT_CONSISTENT, /* Changes are complete */
    511      RT_ADD,        /* Beginning to add a new object */
    512      RT_DELETE      /* Beginning to remove an object */
    513    } r_state;
    514  };
    515 
    516  /* Memory representation of ELF Auxiliary Vectors */
    517  struct AuxVector {
    518    Elf::Addr type;
    519    Elf::Addr value;
    520  };
    521 
    522  /* Helper class used to integrate libraries loaded by this linker in
    523   * r_debug */
    524  class DebuggerHelper {
    525   public:
    526    DebuggerHelper();
    527 
    528    void Init(AuxVector* auvx);
    529 
    530    explicit operator bool() { return dbg; }
    531 
    532    /* Make the debugger aware of a new loaded object */
    533    void Add(link_map* map);
    534 
    535    /* Make the debugger aware of the unloading of an object */
    536    void Remove(link_map* map);
    537 
    538    /* Iterates over all link_maps */
    539    class iterator {
    540     public:
    541      const link_map* operator->() const { return item; }
    542 
    543      const link_map& operator++() {
    544        item = item->l_next;
    545        return *item;
    546      }
    547 
    548      bool operator<(const iterator& other) const {
    549        if (other.item == nullptr) return item ? true : false;
    550        MOZ_CRASH(
    551            "DebuggerHelper::iterator::operator< called with something else "
    552            "than DebuggerHelper::end()");
    553      }
    554 
    555     protected:
    556      friend class DebuggerHelper;
    557      explicit iterator(const link_map* item) : item(item) {}
    558 
    559     private:
    560      const link_map* item;
    561    };
    562 
    563    iterator begin() const { return iterator(dbg ? dbg->r_map : nullptr); }
    564 
    565    iterator end() const { return iterator(nullptr); }
    566 
    567   private:
    568    r_debug* dbg;
    569    link_map* firstAdded;
    570  };
    571  friend int __wrap_dl_iterate_phdr(dl_phdr_cb callback, void* data);
    572  DebuggerHelper dbg;
    573 };
    574 
    575 #endif /* ElfLoader_h */