From ad1d0aa305e2ada610745accee6abf1972423508 Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Tue, 16 Jul 2019 15:23:18 +0300 Subject: [Tizen] Implement detecting of sanitized libraries Parse ".dynamic" section (ELF dynamic array tags) of the module being added, find ".rel(a).plt" section and search it for presence of '__asan_init' symbol. Change-Id: Ie7cc4c818b791b5f00713b42ba15131325b8152c Signed-off-by: Andrey Drobyshev --- src/pal/inc/pal.h | 8 ++ src/pal/src/CMakeLists.txt | 6 ++ src/pal/src/include/pal/module.h | 4 + src/pal/src/loader/module.cpp | 23 ++++++ src/pal/src/loader/tizenasanenvmodule.cpp | 133 ++++++++++++++++++++++++++++++ src/pal/src/loader/tizenasanenvmodule.h | 8 ++ 6 files changed, 182 insertions(+) create mode 100644 src/pal/src/loader/tizenasanenvmodule.cpp create mode 100644 src/pal/src/loader/tizenasanenvmodule.h diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index 76e04cdbdb..45364c9695 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -490,6 +490,14 @@ PALAPI PAL_UnregisterModule( IN HINSTANCE hInstance); +#ifdef TIZEN_ASAN_ENVIRONMENT +PALIMPORT +BOOL +PALAPI +PAL_IsSanitizedModule( + IN HINSTANCE hInstance); +#endif + PALIMPORT BOOL PALAPI diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt index 8e69ee9ee9..7a927f49a4 100644 --- a/src/pal/src/CMakeLists.txt +++ b/src/pal/src/CMakeLists.txt @@ -281,6 +281,12 @@ set(SOURCES thread/tls.cpp ) +if (TIZEN_ASAN_ENVIRONMENT) + list(APPEND SOURCES + loader/tizenasanenvmodule.cpp + ) +endif() + if(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND) set(LIBUNWIND_OBJECTS $) endif(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND) diff --git a/src/pal/src/include/pal/module.h b/src/pal/src/include/pal/module.h index aacc326c64..d2ee88f30f 100644 --- a/src/pal/src/include/pal/module.h +++ b/src/pal/src/include/pal/module.h @@ -39,6 +39,10 @@ typedef struct _MODSTRUCT /* -1 means infinite reference count - module is never released */ BOOL threadLibCalls; /* TRUE for DLL_THREAD_ATTACH/DETACH notifications enabled, FALSE if they are disabled */ +#ifdef TIZEN_ASAN_ENVIRONMENT + BOOL is_sanitized; +#endif + #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN ino_t inode; dev_t device; diff --git a/src/pal/src/loader/module.cpp b/src/pal/src/loader/module.cpp index e39cd6e41f..4dc06d0944 100644 --- a/src/pal/src/loader/module.cpp +++ b/src/pal/src/loader/module.cpp @@ -60,6 +60,10 @@ SET_DEFAULT_DEBUG_CHANNEL(LOADER); // some headers have code with asserts, so do #include #endif +#ifdef TIZEN_ASAN_ENVIRONMENT +#include "tizenasanenvmodule.h" +#endif // TIZEN_ASAN_ENVIRONMENT + using namespace CorUnix; // In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable @@ -802,6 +806,17 @@ PAL_UnregisterModule( PERF_EXIT(PAL_UnregisterModule); } +#ifdef TIZEN_ASAN_ENVIRONMENT +PALIMPORT +BOOL +PALAPI +PAL_IsSanitizedModule( + IN HINSTANCE hInstance) +{ + return ((MODSTRUCT *)hInstance)->is_sanitized; +} +#endif // TIZEN_ASAN_ENVIRONMENT + /*++ PAL_LOADLoadPEFile @@ -1548,6 +1563,10 @@ static MODSTRUCT *LOADAllocModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR name) #else // NEED_DLCOMPAT module->refcount = 1; #endif // NEED_DLCOMPAT + +#ifdef TIZEN_ASAN_ENVIRONMENT + module->is_sanitized = FALSE; +#endif // TIZEN_ASAN_ENVIRONMENT module->self = module; module->hinstance = nullptr; module->threadLibCalls = TRUE; @@ -1622,6 +1641,10 @@ static MODSTRUCT *LOADAddModule(NATIVE_LIBRARY_HANDLE dl_handle, LPCSTR libraryN exe_module.prev->next = module; exe_module.prev = module; +#ifdef TIZEN_ASAN_ENVIRONMENT + module->is_sanitized = module_is_sanitized(dl_handle); +#endif // TIZEN_ASAN_ENVIRONMENT + #if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN module->inode = stat_buf.st_ino; module->device = stat_buf.st_dev; diff --git a/src/pal/src/loader/tizenasanenvmodule.cpp b/src/pal/src/loader/tizenasanenvmodule.cpp new file mode 100644 index 0000000000..9c08c5e552 --- /dev/null +++ b/src/pal/src/loader/tizenasanenvmodule.cpp @@ -0,0 +1,133 @@ +#include +#include "pal.h" +#include "llvm/ELF.h" +#include "tizenasanenvmodule.h" + +#include + +#define __ELF_WORD_SIZE __WORDSIZE + +#define __ELF_CONCAT1(x,y) x ## y +#define __ELF_CONCAT(x,y) __ELF_CONCAT1(x,y) + +#define __ElfN(x) __ELF_CONCAT(__ELF_CONCAT( \ + __ELF_CONCAT(Elf,__ELF_WORD_SIZE), \ + _), \ + x) +#define __ElfType(x) typedef __ElfN(x) __ELF_CONCAT(Elf_,x) + +/* + * Request arguments for dlinfo(). + */ +#define RTLD_DI_LINKMAP 2 /* Obtain link map. */ + +struct link_map { + __ElfN(Addr) l_addr; /* Base Address of library */ + const char *l_name; /* Absolute Path to Library */ + __ElfN(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 { + void *dl_handle; + struct link_map *lm; + __ElfN(Dyn) *dynamic; // .dynamic section + __ElfN(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(void *handle) + : dl_handle(handle), lm(nullptr), dynamic(nullptr), dynsym(nullptr), + dynstr(nullptr), reltype(-1), pltrel_size(0), jmprel(nullptr) + { + if (handle == nullptr || + dlinfo(handle, RTLD_DI_LINKMAP, &lm) < 0 || + lm == nullptr) + return; + dynamic = lm->l_ld; + } + + void walk_dynamic_section() + { + if (dynamic == nullptr) + return; + + for (__ElfN(Dyn) *dyn = dynamic; dyn->d_tag != DT_NULL; dyn++) { + switch (dyn->d_tag) { + case DT_SYMTAB: + dynsym = reinterpret_cast<__ElfN(Sym) *>(dyn->d_un.d_ptr); + break; + case DT_STRTAB: + dynstr = reinterpret_cast(dyn->d_un.d_ptr); + break; + case DT_JMPREL: + jmprel = reinterpret_cast(dyn->d_un.d_ptr); + break; + case DT_PLTRELSZ: + pltrel_size = dyn->d_un.d_val; + break; + case DT_PLTREL: + reltype = dyn->d_un.d_val; + break; + default: + break; + } + } + } + + bool symbol_is_available(const char *sym) const + { + if (jmprel == nullptr) + return false; + + switch (reltype) { + case DT_REL: + return do_symbol_is_available(reinterpret_cast<__ElfN(Rel) *>(jmprel), sym); + break; + case DT_RELA: + return do_symbol_is_available(reinterpret_cast<__ElfN(Rela) *>(jmprel), sym); + break; + default: // no relocations + break; + } + return false; + } + +private: + plt_sym_resolver(); + + template + bool do_symbol_is_available(const Rel *rel_table, const char *sym) const + { + if (rel_table == nullptr || pltrel_size == 0) + return false; + + size_t rel_cnt = pltrel_size / sizeof(Rel); + for (const Rel *rel = rel_table, *rel_end = rel_table + rel_cnt; + 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 module_is_sanitized(void *handle) +{ + plt_sym_resolver psr(handle); + psr.walk_dynamic_section(); + return psr.symbol_is_available("__asan_init") ? TRUE : FALSE; +} diff --git a/src/pal/src/loader/tizenasanenvmodule.h b/src/pal/src/loader/tizenasanenvmodule.h new file mode 100644 index 0000000000..175c8d7c97 --- /dev/null +++ b/src/pal/src/loader/tizenasanenvmodule.h @@ -0,0 +1,8 @@ +#ifndef TIZENASANENVMODULE_H_ +#define TIZENASANENVMODULE_H_ + +#include + +BOOL module_is_sanitized(void *handle); + +#endif // TIZENASANENVMODULE_H_ -- cgit v1.2.3