summaryrefslogtreecommitdiff
path: root/src/pal/src/loader/tizenasanenvmodule.cpp
blob: 4f9ed19863ddb7a9e150ac5f1e1cf4e5311fe036 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <string.h>
#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<Rel *>(jmprel), sym);
        case DT_RELA:
            return is_symbol_available_in_rtable(reinterpret_cast<Rela *>(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<Sym *>(dyn->d_un.d_ptr);
                break;
            case DT_STRTAB:
                dynstr = reinterpret_cast<char *>(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<void *>(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<typename Rel>
    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<typename Rel>
    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;
}