Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/common/libelf/libelf-tools.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * various helper functions to access elf structures
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation;
7
 * version 2.1 of the License.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
#include "libelf-private.h"
19
20
/* ------------------------------------------------------------------------ */
21
22
void elf_mark_broken(struct elf_binary *elf, const char *msg)
23
0
{
24
0
    if ( elf->broken == NULL )
25
0
        elf->broken = msg;
26
0
}
27
28
const char *elf_check_broken(const struct elf_binary *elf)
29
0
{
30
0
    return elf->broken;
31
0
}
32
33
static bool elf_ptrval_in_range(elf_ptrval ptrval, uint64_t size,
34
                               const void *region, uint64_t regionsize)
35
    /*
36
     * Returns true if the putative memory area [ptrval,ptrval+size>
37
     * is completely inside the region [region,region+regionsize>.
38
     *
39
     * ptrval and size are the untrusted inputs to be checked.
40
     * region and regionsize are trusted and must be correct and valid,
41
     * although it is OK for region to perhaps be maliciously NULL
42
     * (but not some other malicious value).
43
     */
44
1.19k
{
45
1.19k
    elf_ptrval regionp = (elf_ptrval)region;
46
1.19k
47
1.19k
    if ( (region == NULL) ||
48
1.19k
         (ptrval < regionp) ||              /* start is before region */
49
1.17k
         (ptrval > regionp + regionsize) || /* start is after region */
50
1.14k
         (size > regionsize - (ptrval - regionp)) ) /* too big */
51
52
        return 0;
52
1.14k
    return 1;
53
1.19k
}
54
55
bool elf_access_ok(struct elf_binary * elf,
56
                  uint64_t ptrval, size_t size)
57
1.14k
{
58
1.14k
    if ( elf_ptrval_in_range(ptrval, size, elf->image_base, elf->size) )
59
1.11k
        return 1;
60
26
    if ( elf_ptrval_in_range(ptrval, size, elf->dest_base, elf->dest_size) )
61
0
        return 1;
62
26
    if ( elf_ptrval_in_range(ptrval, size, elf->xdest_base, elf->xdest_size) )
63
26
        return 1;
64
0
    elf_mark_broken(elf, "out of range access");
65
0
    return 0;
66
26
}
67
68
void elf_memcpy_safe(struct elf_binary *elf, elf_ptrval dst,
69
                     elf_ptrval src, size_t size)
70
3
{
71
3
    if ( elf_access_ok(elf, dst, size) &&
72
3
         elf_access_ok(elf, src, size) )
73
3
    {
74
3
        /* use memmove because these checks do not prove that the
75
3
         * regions don't overlap and overlapping regions grant
76
3
         * permission for compiler malice */
77
3
        elf_memmove_unchecked(ELF_UNSAFE_PTR(dst), ELF_UNSAFE_PTR(src), size);
78
3
    }
79
3
}
80
81
void elf_memset_safe(struct elf_binary *elf, elf_ptrval dst, int c, size_t size)
82
1
{
83
1
    if ( elf_access_ok(elf, dst, size) )
84
1
    {
85
1
        elf_memset_unchecked(ELF_UNSAFE_PTR(dst), c, size);
86
1
    }
87
1
}
88
89
uint64_t elf_access_unsigned(struct elf_binary * elf, elf_ptrval base,
90
                             uint64_t moreoffset, size_t size)
91
799
{
92
799
    elf_ptrval ptrval = base + moreoffset;
93
799
    bool need_swap = elf_swap(elf);
94
799
    const uint8_t *u8;
95
799
    const uint16_t *u16;
96
799
    const uint32_t *u32;
97
799
    const uint64_t *u64;
98
799
99
799
    if ( !elf_access_ok(elf, ptrval, size) )
100
0
        return 0;
101
799
102
799
    switch ( size )
103
799
    {
104
197
    case 1:
105
197
        u8 = (const void*)ptrval;
106
197
        return *u8;
107
249
    case 2:
108
249
        u16 = (const void*)ptrval;
109
249
        return need_swap ? bswap_16(*u16) : *u16;
110
200
    case 4:
111
200
        u32 = (const void*)ptrval;
112
200
        return need_swap ? bswap_32(*u32) : *u32;
113
153
    case 8:
114
153
        u64 = (const void*)ptrval;
115
153
        return need_swap ? bswap_64(*u64) : *u64;
116
0
    default:
117
0
        return 0;
118
799
    }
119
799
}
120
121
uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr)
122
6
{
123
6
    uint64_t elf_round = (elf_64bit(elf) ? 8 : 4) - 1;
124
6
125
6
    return (addr + elf_round) & ~elf_round;
126
6
}
127
128
/* ------------------------------------------------------------------------ */
129
130
unsigned elf_shdr_count(struct elf_binary *elf)
131
104
{
132
104
    unsigned count = elf_uval(elf, elf->ehdr, e_shnum);
133
104
    uint64_t max = elf->size / sizeof(Elf32_Shdr);
134
104
135
104
    if ( max > UINT_MAX )
136
0
        max = UINT_MAX;
137
104
    if ( count > max )
138
0
    {
139
0
        elf_mark_broken(elf, "far too many section headers");
140
0
        count = max;
141
0
    }
142
104
    return count;
143
104
}
144
145
unsigned elf_phdr_count(struct elf_binary *elf)
146
22
{
147
22
    return elf_uval(elf, elf->ehdr, e_phnum);
148
22
}
149
150
ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *name)
151
0
{
152
0
    unsigned i, count = elf_shdr_count(elf);
153
0
    ELF_HANDLE_DECL(elf_shdr) shdr;
154
0
    const char *sname;
155
0
156
0
    for ( i = 1; i < count; i++ )
157
0
    {
158
0
        shdr = elf_shdr_by_index(elf, i);
159
0
        if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
160
0
            /* input has an insane section header count field */
161
0
            break;
162
0
        sname = elf_section_name(elf, shdr);
163
0
        if ( sname && !strcmp(sname, name) )
164
0
            return shdr;
165
0
    }
166
0
    return ELF_INVALID_HANDLE(elf_shdr);
167
0
}
168
169
ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_index(struct elf_binary *elf, unsigned index)
170
101
{
171
101
    unsigned count = elf_shdr_count(elf);
172
101
    elf_ptrval ptr;
173
101
174
101
    if ( index >= count )
175
0
        return ELF_INVALID_HANDLE(elf_shdr);
176
101
177
101
    ptr = (ELF_IMAGE_BASE(elf)
178
101
           + elf_uval(elf, elf->ehdr, e_shoff)
179
101
           + elf_uval(elf, elf->ehdr, e_shentsize) * index);
180
101
    return ELF_MAKE_HANDLE(elf_shdr, ptr);
181
101
}
182
183
ELF_HANDLE_DECL(elf_phdr) elf_phdr_by_index(struct elf_binary *elf, unsigned index)
184
18
{
185
18
    unsigned count = elf_phdr_count(elf);
186
18
    elf_ptrval ptr;
187
18
188
18
    if ( index >= count )
189
0
        return ELF_INVALID_HANDLE(elf_phdr);
190
18
191
18
    ptr = (ELF_IMAGE_BASE(elf)
192
18
           + elf_uval(elf, elf->ehdr, e_phoff)
193
18
           + elf_uval(elf, elf->ehdr, e_phentsize) * index);
194
18
    return ELF_MAKE_HANDLE(elf_phdr, ptr);
195
18
}
196
197
198
const char *elf_section_name(struct elf_binary *elf,
199
                             ELF_HANDLE_DECL(elf_shdr) shdr)
200
0
{
201
0
    if ( ELF_PTRVAL_INVALID(elf->sec_strtab) )
202
0
        return "unknown";
203
0
204
0
    return elf_strval(elf, elf->sec_strtab + elf_uval(elf, shdr, sh_name));
205
0
}
206
207
const char *elf_strval(struct elf_binary *elf, elf_ptrval start)
208
22
{
209
22
    uint64_t length;
210
22
211
195
    for ( length = 0; ; length++ ) {
212
195
        if ( !elf_access_ok(elf, start + length, 1) )
213
0
            return NULL;
214
195
        if ( !elf_access_unsigned(elf, start, length, 1) )
215
195
            /* ok */
216
22
            return ELF_UNSAFE_PTR(start);
217
173
        if ( length >= ELF_MAX_STRING_LENGTH )
218
0
        {
219
0
            elf_mark_broken(elf, "excessively long string");
220
0
            return NULL;
221
0
        }
222
173
    }
223
22
}
224
225
const char *elf_strfmt(struct elf_binary *elf, elf_ptrval start)
226
0
{
227
0
    const char *str = elf_strval(elf, start);
228
0
229
0
    if ( str == NULL )
230
0
        return "(invalid)";
231
0
    return str;
232
0
}
233
234
elf_ptrval elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr)
235
5
{
236
5
    return ELF_IMAGE_BASE(elf) + elf_uval(elf, shdr, sh_offset);
237
5
}
238
239
elf_ptrval elf_section_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr)
240
1
{
241
1
    return ELF_IMAGE_BASE(elf)
242
1
        + elf_uval(elf, shdr, sh_offset) + elf_uval(elf, shdr, sh_size);
243
1
}
244
245
elf_ptrval elf_segment_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
246
0
{
247
0
    return ELF_IMAGE_BASE(elf)
248
0
        + elf_uval(elf, phdr, p_offset);
249
0
}
250
251
elf_ptrval elf_segment_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
252
0
{
253
0
    return ELF_IMAGE_BASE(elf)
254
0
        + elf_uval(elf, phdr, p_offset) + elf_uval(elf, phdr, p_filesz);
255
0
}
256
257
ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *symbol)
258
0
{
259
0
    elf_ptrval ptr = elf_section_start(elf, elf->sym_tab);
260
0
    elf_ptrval end = elf_section_end(elf, elf->sym_tab);
261
0
    ELF_HANDLE_DECL(elf_sym) sym;
262
0
    uint64_t info, name;
263
0
    const char *sym_name;
264
0
265
0
    for ( ; ptr < end; ptr += elf_size(elf, sym) )
266
0
    {
267
0
        sym = ELF_MAKE_HANDLE(elf_sym, ptr);
268
0
        info = elf_uval(elf, sym, st_info);
269
0
        name = elf_uval(elf, sym, st_name);
270
0
        if ( ELF32_ST_BIND(info) != STB_GLOBAL )
271
0
            continue;
272
0
        sym_name = elf_strval(elf, elf->sym_strtab + name);
273
0
        if ( sym_name == NULL ) /* out of range, oops */
274
0
            return ELF_INVALID_HANDLE(elf_sym);
275
0
        if ( strcmp(sym_name, symbol) )
276
0
            continue;
277
0
        return sym;
278
0
    }
279
0
    return ELF_INVALID_HANDLE(elf_sym);
280
0
}
281
282
ELF_HANDLE_DECL(elf_sym) elf_sym_by_index(struct elf_binary *elf, unsigned index)
283
0
{
284
0
    elf_ptrval ptr = elf_section_start(elf, elf->sym_tab);
285
0
    ELF_HANDLE_DECL(elf_sym) sym;
286
0
287
0
    sym = ELF_MAKE_HANDLE(elf_sym, ptr + index * elf_size(elf, sym));
288
0
    return sym;
289
0
}
290
291
const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
292
15
{
293
15
    return elf_strval(elf, ELF_HANDLE_PTRVAL(note) + elf_size(elf, note));
294
15
}
295
296
elf_ptrval elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
297
14
{
298
14
    unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
299
14
300
14
    return ELF_HANDLE_PTRVAL(note) + elf_size(elf, note) + namesz;
301
14
}
302
303
uint64_t elf_note_numeric(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
304
7
{
305
7
    elf_ptrval desc = elf_note_desc(elf, note);
306
7
    unsigned descsz = elf_uval(elf, note, descsz);
307
7
308
7
    switch (descsz)
309
7
    {
310
7
    case 1:
311
7
    case 2:
312
7
    case 4:
313
7
    case 8:
314
7
        return elf_access_unsigned(elf, desc, 0, descsz);
315
0
    default:
316
0
        return 0;
317
7
    }
318
7
}
319
320
uint64_t elf_note_numeric_array(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note,
321
                                unsigned int unitsz, unsigned int idx)
322
0
{
323
0
    elf_ptrval desc = elf_note_desc(elf, note);
324
0
    unsigned descsz = elf_uval(elf, note, descsz);
325
0
326
0
    if ( descsz % unitsz || idx >= descsz / unitsz )
327
0
        return 0;
328
0
    switch (unitsz)
329
0
    {
330
0
    case 1:
331
0
    case 2:
332
0
    case 4:
333
0
    case 8:
334
0
        return elf_access_unsigned(elf, desc, idx * unitsz, unitsz);
335
0
    default:
336
0
        return 0;
337
0
    }
338
0
}
339
340
ELF_HANDLE_DECL(elf_note) elf_note_next(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
341
15
{
342
15
    unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
343
15
    unsigned descsz = (elf_uval(elf, note, descsz) + 3) & ~3;
344
15
345
15
    elf_ptrval ptrval = ELF_HANDLE_PTRVAL(note)
346
15
        + elf_size(elf, note) + namesz + descsz;
347
15
348
15
    if ( ( ptrval <= ELF_HANDLE_PTRVAL(note) || /* wrapped or stuck */
349
15
           !elf_access_ok(elf, ELF_HANDLE_PTRVAL(note), 1) ) )
350
0
        ptrval = ELF_MAX_PTRVAL; /* terminate caller's loop */
351
15
352
15
    return ELF_MAKE_HANDLE(elf_note, ptrval);
353
15
}
354
355
/* ------------------------------------------------------------------------ */
356
357
bool elf_is_elfbinary(const void *image_start, size_t image_size)
358
3
{
359
3
    const Elf32_Ehdr *ehdr = image_start;
360
3
361
3
    if ( image_size < sizeof(*ehdr) )
362
0
        return 0;
363
3
364
3
    return IS_ELF(*ehdr);
365
3
}
366
367
bool elf_phdr_is_loadable(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr)
368
12
{
369
12
    uint64_t p_type = elf_uval(elf, phdr, p_type);
370
12
    uint64_t p_flags = elf_uval(elf, phdr, p_flags);
371
12
372
12
    return ((p_type == PT_LOAD) && (p_flags & (PF_R | PF_W | PF_X)) != 0);
373
12
}
374
375
void elf_set_xdest(struct elf_binary *elf, void *addr, uint64_t size)
376
2
{
377
2
    elf->xdest_base = addr;
378
2
    elf->xdest_size = size;
379
2
    if ( addr != NULL )
380
1
        elf_memset_safe(elf, ELF_REALPTR2PTRVAL(addr), 0, size);
381
2
}
382
383
/*
384
 * Local variables:
385
 * mode: C
386
 * c-file-style: "BSD"
387
 * c-basic-offset: 4
388
 * tab-width: 4
389
 * indent-tabs-mode: nil
390
 * End:
391
 */