[Tizen] Implement detecting of sanitized libraries
authorAndrey Drobyshev <a.drobyshev@samsung.com>
Tue, 16 Jul 2019 12:23:18 +0000 (15:23 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Fri, 26 Jul 2019 10:54:06 +0000 (13:54 +0300)
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 <a.drobyshev@samsung.com>
src/pal/inc/pal.h
src/pal/src/CMakeLists.txt
src/pal/src/include/pal/module.h
src/pal/src/loader/module.cpp
src/pal/src/loader/tizenasanenvmodule.cpp [new file with mode: 0644]
src/pal/src/loader/tizenasanenvmodule.h [new file with mode: 0644]

index 76e04cd..45364c9 100644 (file)
@@ -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
index 8e69ee9..7a927f4 100644 (file)
@@ -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 $<TARGET_OBJECTS:libunwind>)
 endif(NOT CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
index aacc326..d2ee88f 100644 (file)
@@ -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;
index e39cd6e..4dc06d0 100644 (file)
@@ -60,6 +60,10 @@ SET_DEFAULT_DEBUG_CHANNEL(LOADER); // some headers have code with asserts, so do
 #include <gnu/lib-names.h>
 #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 (file)
index 0000000..9c08c5e
--- /dev/null
@@ -0,0 +1,133 @@
+#include <string.h>
+#include "pal.h"
+#include "llvm/ELF.h"
+#include "tizenasanenvmodule.h"
+
+#include <bits/wordsize.h>
+
+#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<char *>(dyn->d_un.d_ptr);
+                break;
+            case DT_JMPREL:
+                jmprel = reinterpret_cast<void *>(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<typename Rel>
+    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<typename Rel>
+    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 (file)
index 0000000..175c8d7
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef TIZENASANENVMODULE_H_
+#define TIZENASANENVMODULE_H_
+
+#include <pal_mstypes.h>
+
+BOOL module_is_sanitized(void *handle);
+
+#endif // TIZENASANENVMODULE_H_