#include #include "pal.h" #include "llvm/ELF.h" #include "tizenasanenvmodule.h" #if __LP64__ using Addr = Elf64_Addr; using Dyn = Elf64_Dyn; using Sym = Elf64_Sym; using Rel = Elf64_Rel; using Rela = Elf64_Rela; #else using Addr = Elf32_Addr; using Dyn = Elf32_Dyn; using Sym = Elf32_Sym; using Rel = Elf32_Rel; using Rela = Elf32_Rela; #endif /* * Request arguments for dlinfo(). */ #define RTLD_DI_LINKMAP 2 /* Obtain link map. */ struct link_map { Addr l_addr; /* Base Address of library */ const char *l_name; /* Absolute Path to Library */ Dyn *l_ld; /* Pointer to .dynamic in memory */ struct link_map *l_next, *l_prev; /* linked list of of mapped libs */ }; extern "C" int dlinfo(void *handle, int request, void *info); struct plt_sym_resolver { Sym *dynsym; // .dynsym section char *dynstr; // .dynstr section long reltype; // relocation type size_t pltrel_size; // size of .rel(a).plt section void *jmprel; // .rel(a).plt section. Exact relocation // type is resolved at runtime plt_sym_resolver() : dynsym(nullptr), dynstr(nullptr), reltype(-1), pltrel_size(0), jmprel(nullptr) {} bool init(void *handle) { struct link_map *lmap; if (handle == nullptr || dlinfo(handle, RTLD_DI_LINKMAP, &lmap) < 0) return false; if (lmap == nullptr || lmap->l_ld == nullptr) return false; return init_relocation_info(lmap->l_ld); } bool is_symbol_available(const char *sym) const { switch (reltype) { case DT_REL: return is_symbol_available_in_rtable(reinterpret_cast(jmprel), sym); case DT_RELA: return is_symbol_available_in_rtable(reinterpret_cast(jmprel), sym); default: // no relocations break; } return false; } private: bool init_relocation_info(Dyn *dynamic) { for (Dyn *dyn = dynamic; dyn->d_tag != DT_NULL; ++dyn) { switch (dyn->d_tag) { case DT_SYMTAB: dynsym = reinterpret_cast(dyn->d_un.d_ptr); break; case DT_STRTAB: dynstr = reinterpret_cast(dyn->d_un.d_ptr); break; case DT_PLTREL: reltype = dyn->d_un.d_val; break; case DT_PLTRELSZ: pltrel_size = dyn->d_un.d_val; break; case DT_JMPREL: jmprel = reinterpret_cast(dyn->d_un.d_ptr); break; default: break; } } if (dynsym == nullptr || dynstr == nullptr || jmprel == nullptr || pltrel_size == 0 || (reltype != DT_REL && reltype != DT_RELA)) return false; return true; } template bool is_symbol_available_in_rtable(const Rel *rel_table, const char *sym) const { if (rel_table == nullptr || pltrel_size == 0) return false; const size_t rel_cnt = pltrel_size / sizeof(Rel); const Rel *rel_end = rel_table + rel_cnt; for (const Rel *rel = rel_table; rel < rel_end; ++rel) { if (strcmp(sym, rel_to_symname(rel)) == 0) return true; } return false; } template inline char *rel_to_symname(const Rel *rel) const { return dynstr + dynsym[rel->getSymbol()].st_name; } }; BOOL is_module_sanitized(void *handle) { plt_sym_resolver psr; if (!psr.init(handle)) return FALSE; return psr.is_symbol_available("__asan_init") ? TRUE : FALSE; }