X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Flttng-elf.c;h=d6cef2fe8632fe08aa150e7816865e86fd3e79bc;hp=5d3aaad04bf098a5fc60f1407c5a2bad8f6e547d;hb=983a481e7516ab54b3697a28aa16a81f51573152;hpb=d3be549561ae1a35dba8f2b0eb400f06980a390c diff --git a/src/common/lttng-elf.c b/src/common/lttng-elf.c index 5d3aaad04..d6cef2fe8 100644 --- a/src/common/lttng-elf.c +++ b/src/common/lttng-elf.c @@ -1,21 +1,10 @@ /* - * Copyright (C) 2015 Antoine Busque - * Copyright (C) 2017 Francis Deslauriers - * Copyright (C) 2017 Erica Bugden + * Copyright (C) 2015 Antoine Busque + * Copyright (C) 2017 Francis Deslauriers + * Copyright (C) 2017 Erica Bugden * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * SPDX-License-Identifier: LGPL-2.1-or-later * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include @@ -38,9 +27,12 @@ #define TEXT_SECTION_NAME ".text" #define SYMBOL_TAB_SECTION_NAME ".symtab" #define STRING_TAB_SECTION_NAME ".strtab" +#define DYNAMIC_SYMBOL_TAB_SECTION_NAME ".dynsym" +#define DYNAMIC_STRING_TAB_SECTION_NAME ".dynstr" #define NOTE_STAPSDT_SECTION_NAME ".note.stapsdt" #define NOTE_STAPSDT_NAME "stapsdt" #define NOTE_STAPSDT_TYPE 3 +#define MAX_SECTION_DATA_SIZE 512 * 1024 * 1024 #if BYTE_ORDER == LITTLE_ENDIAN #define NATIVE_ELF_ENDIANNESS ELFDATA2LSB @@ -54,13 +46,13 @@ do { \ switch (sizeof(x)) { \ case 8: \ - x = be64toh(x); \ + x = be64toh((uint64_t)x); \ break; \ case 4: \ - x = be32toh(x); \ + x = be32toh((uint32_t)x); \ break; \ case 2: \ - x = be16toh(x); \ + x = be16toh((uint16_t)x); \ break; \ case 1: \ break; \ @@ -141,8 +133,17 @@ dst_sym.st_size = src_sym.st_size; \ } while (0) -/* Both 32bit and 64bit use the same 1 byte field for type. (See elf.h) */ -#define ELF_ST_TYPE(val) ELF32_ST_TYPE(val) +#ifndef ELFCLASSNUM +#define ELFCLASSNUM 3 +#endif + +#ifndef ELFDATANUM +#define ELFDATANUM 3 +#endif + +#ifndef EV_NUM +#define EV_NUM 2 +#endif struct lttng_elf_ehdr { uint16_t e_type; @@ -189,6 +190,7 @@ struct lttng_elf_sym { struct lttng_elf { int fd; + size_t file_size; uint8_t bitness; uint8_t endianness; /* Offset in bytes to start of section names string table. */ @@ -307,39 +309,32 @@ error: * Retrieve the nth (where n is the `index` argument) shdr (section * header) from the given elf instance. * - * A pointer to the shdr is returned on success, NULL on failure. + * 0 is returned on succes, -1 on failure. */ static -struct lttng_elf_shdr *lttng_elf_get_section_hdr(struct lttng_elf *elf, - uint16_t index) +int lttng_elf_get_section_hdr(struct lttng_elf *elf, + uint16_t index, struct lttng_elf_shdr *out_header) { - struct lttng_elf_shdr *section_header = NULL; int ret = 0; if (!elf) { + ret = -1; goto error; } if (index >= elf->ehdr->e_shnum) { + ret = -1; goto error; } - section_header = zmalloc(sizeof(struct lttng_elf_shdr)); - if (!section_header) { - goto error; - } - - ret = populate_section_header(elf, section_header, index); + ret = populate_section_header(elf, out_header, index); if (ret) { - ret = LTTNG_ERR_ELF_PARSING; DBG("Error populating section header."); goto error; } - return section_header; error: - free(section_header); - return NULL; + return ret; } /* @@ -533,19 +528,31 @@ end: static struct lttng_elf *lttng_elf_create(int fd) { - struct lttng_elf_shdr *section_names_shdr; + struct lttng_elf_shdr section_names_shdr; struct lttng_elf *elf = NULL; int ret; + struct stat stat_buf; if (fd < 0) { goto error; } + ret = fstat(fd, &stat_buf); + if (ret) { + PERROR("Failed to determine size of elf file"); + goto error; + } + if (!S_ISREG(stat_buf.st_mode)) { + ERR("Refusing to initialize lttng_elf from non-regular file"); + goto error; + } + elf = zmalloc(sizeof(struct lttng_elf)); if (!elf) { PERROR("Error allocating struct lttng_elf"); goto error; } + elf->file_size = (size_t) stat_buf.st_size; elf->fd = dup(fd); if (elf->fd < 0) { @@ -558,15 +565,14 @@ struct lttng_elf *lttng_elf_create(int fd) goto error; } - section_names_shdr = lttng_elf_get_section_hdr(elf, elf->ehdr->e_shstrndx); - if (!section_names_shdr) { + ret = lttng_elf_get_section_hdr( + elf, elf->ehdr->e_shstrndx, §ion_names_shdr); + if (ret) { goto error; } - elf->section_names_offset = section_names_shdr->sh_offset; - elf->section_names_size = section_names_shdr->sh_size; - - free(section_names_shdr); + elf->section_names_offset = section_names_shdr.sh_offset; + elf->section_names_size = section_names_shdr.sh_size; return elf; error: @@ -605,19 +611,26 @@ void lttng_elf_destroy(struct lttng_elf *elf) static int lttng_elf_get_section_hdr_by_name(struct lttng_elf *elf, - const char *section_name, struct lttng_elf_shdr **section_hdr) + const char *section_name, struct lttng_elf_shdr *section_hdr) { int i; char *curr_section_name; + for (i = 0; i < elf->ehdr->e_shnum; ++i) { - *section_hdr = lttng_elf_get_section_hdr(elf, i); - curr_section_name = lttng_elf_get_section_name(elf, - (*section_hdr)->sh_name); + bool name_equal; + int ret = lttng_elf_get_section_hdr(elf, i, section_hdr); + if (ret) { + break; + } + curr_section_name = lttng_elf_get_section_name(elf, + section_hdr->sh_name); if (!curr_section_name) { continue; } - if (strcmp(curr_section_name, section_name) == 0) { + name_equal = strcmp(curr_section_name, section_name) == 0; + free(curr_section_name); + if (name_equal) { return 0; } } @@ -631,17 +644,25 @@ char *lttng_elf_get_section_data(struct lttng_elf *elf, int ret; off_t section_offset; char *data; + size_t max_alloc_size; if (!elf || !shdr) { goto error; } + max_alloc_size = min_t(size_t, MAX_SECTION_DATA_SIZE, elf->file_size); + section_offset = shdr->sh_offset; if (lseek(elf->fd, section_offset, SEEK_SET) < 0) { PERROR("Error seeking to section offset"); goto error; } + if (shdr->sh_size > max_alloc_size) { + ERR("ELF section size exceeds maximal allowed size of %zu bytes", + max_alloc_size); + goto error; + } data = zmalloc(shdr->sh_size); if (!data) { PERROR("Error allocating buffer for ELF section data"); @@ -677,7 +698,7 @@ int lttng_elf_convert_addr_in_text_to_offset(struct lttng_elf *elf_handle, off_t text_section_addr_beg; off_t text_section_addr_end; off_t offset_in_section; - struct lttng_elf_shdr *text_section_hdr = NULL; + struct lttng_elf_shdr text_section_hdr; if (!elf_handle) { DBG("Invalid ELF handle."); @@ -694,9 +715,10 @@ int lttng_elf_convert_addr_in_text_to_offset(struct lttng_elf *elf_handle, goto error; } - text_section_offset = text_section_hdr->sh_offset; - text_section_addr_beg = text_section_hdr->sh_addr; - text_section_addr_end = text_section_addr_beg + text_section_hdr->sh_size; + text_section_offset = text_section_hdr.sh_offset; + text_section_addr_beg = text_section_hdr.sh_addr; + text_section_addr_end = + text_section_addr_beg + text_section_hdr.sh_size; /* * Verify that the address is within the .text section boundaries. @@ -737,8 +759,9 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) char *curr_sym_str = NULL; char *symbol_table_data = NULL; char *string_table_data = NULL; - struct lttng_elf_shdr *symtab_hdr = NULL; - struct lttng_elf_shdr *strtab_hdr = NULL; + const char *string_table_name = NULL; + struct lttng_elf_shdr symtab_hdr; + struct lttng_elf_shdr strtab_hdr; struct lttng_elf *elf = NULL; if (!symbol || !offset ) { @@ -752,16 +775,31 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) goto end; } - /* Get the symbol table section header. */ + /* + * The .symtab section might not exist on stripped binaries. + * Try to get the symbol table section header first. If it's absent, + * try to get the dynamic symbol table. All symbols in the dynamic + * symbol tab are in the (normal) symbol table if it exists. + */ ret = lttng_elf_get_section_hdr_by_name(elf, SYMBOL_TAB_SECTION_NAME, &symtab_hdr); if (ret) { - DBG("Cannot get ELF Symbol Table section."); - ret = LTTNG_ERR_ELF_PARSING; - goto destroy_elf; + DBG("Cannot get ELF Symbol Table section. Trying to get ELF Dynamic Symbol Table section."); + /* Get the dynamic symbol table section header. */ + ret = lttng_elf_get_section_hdr_by_name(elf, DYNAMIC_SYMBOL_TAB_SECTION_NAME, + &symtab_hdr); + if (ret) { + DBG("Cannot get ELF Symbol Table nor Dynamic Symbol Table sections."); + ret = LTTNG_ERR_ELF_PARSING; + goto destroy_elf; + } + string_table_name = DYNAMIC_STRING_TAB_SECTION_NAME; + } else { + string_table_name = STRING_TAB_SECTION_NAME; } + /* Get the data associated with the symbol table section. */ - symbol_table_data = lttng_elf_get_section_data(elf, symtab_hdr); + symbol_table_data = lttng_elf_get_section_data(elf, &symtab_hdr); if (symbol_table_data == NULL) { DBG("Cannot get ELF Symbol Table data."); ret = LTTNG_ERR_ELF_PARSING; @@ -769,7 +807,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) } /* Get the string table section header. */ - ret = lttng_elf_get_section_hdr_by_name(elf, STRING_TAB_SECTION_NAME, + ret = lttng_elf_get_section_hdr_by_name(elf, string_table_name, &strtab_hdr); if (ret) { DBG("Cannot get ELF string table section."); @@ -777,7 +815,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) } /* Get the data associated with the string table section. */ - string_table_data = lttng_elf_get_section_data(elf, strtab_hdr); + string_table_data = lttng_elf_get_section_data(elf, &strtab_hdr); if (string_table_data == NULL) { DBG("Cannot get ELF string table section data."); ret = LTTNG_ERR_ELF_PARSING; @@ -785,7 +823,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) } /* Get the number of symbol in the table for the iteration. */ - sym_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize; + sym_count = symtab_hdr.sh_size / symtab_hdr.sh_entsize; /* Loop over all symbol. */ for (sym_idx = 0; sym_idx < sym_count; sym_idx++) { @@ -817,7 +855,8 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) /* * If the current symbol is not a function; skip to the next symbol. */ - if (ELF_ST_TYPE(curr_sym.st_info) != STT_FUNC) { + /* Both 32bit and 64bit use the same 1 byte field for type. (See elf.h) */ + if (ELF32_ST_TYPE(curr_sym.st_info) != STT_FUNC) { continue; } @@ -844,7 +883,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) */ ret = lttng_elf_convert_addr_in_text_to_offset(elf, addr, offset); if (ret) { - DBG("Cannot convet addr to offset."); + DBG("Cannot convert addr to offset."); goto free_string_table_data; } @@ -871,7 +910,7 @@ int lttng_elf_get_sdt_probe_offsets(int fd, const char *provider_name, const char *probe_name, uint64_t **offsets, uint32_t *nb_probes) { int ret = 0, nb_match = 0; - struct lttng_elf_shdr *stap_note_section_hdr = NULL; + struct lttng_elf_shdr stap_note_section_hdr; struct lttng_elf *elf = NULL; char *stap_note_section_data = NULL; char *curr_note_section_begin, *curr_data_ptr, *curr_probe, *curr_provider; @@ -902,14 +941,14 @@ int lttng_elf_get_sdt_probe_offsets(int fd, const char *provider_name, } /* Get the data associated with the stap note section. */ - stap_note_section_data = lttng_elf_get_section_data(elf, stap_note_section_hdr); + stap_note_section_data = + lttng_elf_get_section_data(elf, &stap_note_section_hdr); if (stap_note_section_data == NULL) { DBG("Cannot get ELF stap note section data."); ret = LTTNG_ERR_ELF_PARSING; goto destroy_elf_error; } - curr_data_ptr = stap_note_section_data; next_note_ptr = stap_note_section_data; curr_note_section_begin = stap_note_section_data; @@ -918,7 +957,8 @@ int lttng_elf_get_sdt_probe_offsets(int fd, const char *provider_name, curr_data_ptr = next_note_ptr; /* Check if we have reached the end of the note section. */ if (curr_data_ptr >= - curr_note_section_begin + stap_note_section_hdr->sh_size) { + curr_note_section_begin + + stap_note_section_hdr.sh_size) { *nb_probes = nb_match; *offsets = probe_locs; ret = 0; @@ -994,7 +1034,7 @@ int lttng_elf_get_sdt_probe_offsets(int fd, const char *provider_name, */ if (curr_semaphore_location != 0) { ret = LTTNG_ERR_SDT_PROBE_SEMAPHORE; - goto end; + goto realloc_error; } new_size = (++nb_match) * sizeof(uint64_t);