[Tizen] Implement detecting of sanitized libraries
[platform/upstream/coreclr.git] / src / pal / src / loader / tizenasanenvmodule.cpp
1 #include <string.h>
2 #include "pal.h"
3 #include "llvm/ELF.h"
4 #include "tizenasanenvmodule.h"
5
6 #if __LP64__
7 using Addr = Elf64_Addr;
8 using Dyn  = Elf64_Dyn;
9 using Sym  = Elf64_Sym;
10 using Rel  = Elf64_Rel;
11 using Rela = Elf64_Rela;
12 #else
13 using Addr = Elf32_Addr;
14 using Dyn  = Elf32_Dyn;
15 using Sym  = Elf32_Sym;
16 using Rel  = Elf32_Rel;
17 using Rela = Elf32_Rela;
18 #endif
19
20 /*
21  * Request arguments for dlinfo().
22  */
23 #define RTLD_DI_LINKMAP   2   /* Obtain link map. */
24
25 struct link_map {
26     Addr            l_addr;             /* Base Address of library */
27     const char      *l_name;            /* Absolute Path to Library */
28     Dyn             *l_ld;              /* Pointer to .dynamic in memory */
29     struct link_map *l_next, *l_prev;   /* linked list of of mapped libs */
30 };
31
32 extern "C" int dlinfo(void *handle, int request, void *info);
33
34 struct plt_sym_resolver {
35     Sym *dynsym;            // .dynsym section
36     char *dynstr;           // .dynstr section
37     long reltype;           // relocation type
38     size_t pltrel_size;     // size of .rel(a).plt section
39     void *jmprel;           // .rel(a).plt section. Exact relocation
40                             // type is resolved at runtime
41
42     plt_sym_resolver()
43         : dynsym(nullptr), dynstr(nullptr), reltype(-1), pltrel_size(0),
44           jmprel(nullptr)
45     {}
46
47     bool init(void *handle)
48     {
49         struct link_map *lmap;
50
51         if (handle == nullptr || dlinfo(handle, RTLD_DI_LINKMAP, &lmap) < 0)
52             return false;
53
54         if (lmap == nullptr || lmap->l_ld == nullptr)
55             return false;
56
57         return init_relocation_info(lmap->l_ld);
58     }
59
60     bool is_symbol_available(const char *sym) const
61     {
62         switch (reltype) {
63         case DT_REL:
64             return is_symbol_available_in_rtable(reinterpret_cast<Rel *>(jmprel), sym);
65         case DT_RELA:
66             return is_symbol_available_in_rtable(reinterpret_cast<Rela *>(jmprel), sym);
67         default:    // no relocations
68             break;
69        }
70        return false;
71     }
72
73 private:
74     bool init_relocation_info(Dyn *dynamic)
75     {
76         for (Dyn *dyn = dynamic; dyn->d_tag != DT_NULL; ++dyn) {
77             switch (dyn->d_tag) {
78             case DT_SYMTAB:
79                 dynsym = reinterpret_cast<Sym *>(dyn->d_un.d_ptr);
80                 break;
81             case DT_STRTAB:
82                 dynstr = reinterpret_cast<char *>(dyn->d_un.d_ptr);
83                 break;
84             case DT_PLTREL:
85                 reltype = dyn->d_un.d_val;
86                 break;
87             case DT_PLTRELSZ:
88                 pltrel_size = dyn->d_un.d_val;
89                 break;
90             case DT_JMPREL:
91                 jmprel = reinterpret_cast<void *>(dyn->d_un.d_ptr);
92                 break;
93             default:
94                 break;
95             }
96         }
97
98         if (dynsym == nullptr ||
99             dynstr == nullptr ||
100             jmprel == nullptr ||
101             pltrel_size == 0 ||
102             (reltype != DT_REL && reltype != DT_RELA))
103             return false;
104
105         return true;
106     }
107
108     template<typename Rel>
109     bool is_symbol_available_in_rtable(const Rel *rel_table, const char *sym) const
110     {
111         if (rel_table == nullptr || pltrel_size == 0)
112             return false;
113
114         const size_t rel_cnt = pltrel_size / sizeof(Rel);
115         const Rel *rel_end = rel_table + rel_cnt;
116         for (const Rel *rel = rel_table; rel < rel_end; ++rel) {
117             if (strcmp(sym, rel_to_symname(rel)) == 0)
118                 return true;
119         }
120
121         return false;
122     }
123
124     template<typename Rel>
125     inline char *rel_to_symname(const Rel *rel) const
126     {
127         return dynstr + dynsym[rel->getSymbol()].st_name;
128     }
129 };
130
131 BOOL is_module_sanitized(void *handle)
132 {
133     plt_sym_resolver psr;
134     if (!psr.init(handle))
135         return FALSE;
136     return psr.is_symbol_available("__asan_init") ? TRUE : FALSE;
137 }