Branch data Line data Source code
1 : : /* Return string pointer from string section. 2 : : Copyright (C) 1998-2002, 2004, 2008, 2009, 2015 Red Hat, Inc. 3 : : This file is part of elfutils. 4 : : Contributed by Ulrich Drepper <drepper@redhat.com>, 1998. 5 : : 6 : : This file is free software; you can redistribute it and/or modify 7 : : it under the terms of either 8 : : 9 : : * the GNU Lesser General Public License as published by the Free 10 : : Software Foundation; either version 3 of the License, or (at 11 : : your option) any later version 12 : : 13 : : or 14 : : 15 : : * the GNU General Public License as published by the Free 16 : : Software Foundation; either version 2 of the License, or (at 17 : : your option) any later version 18 : : 19 : : or both in parallel, as here. 20 : : 21 : : elfutils is distributed in the hope that it will be useful, but 22 : : WITHOUT ANY WARRANTY; without even the implied warranty of 23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 : : General Public License for more details. 25 : : 26 : : You should have received copies of the GNU General Public License and 27 : : the GNU Lesser General Public License along with this program. If 28 : : not, see <http://www.gnu.org/licenses/>. */ 29 : : 30 : : #ifdef HAVE_CONFIG_H 31 : : # include <config.h> 32 : : #endif 33 : : 34 : : #include <libelf.h> 35 : : #include <stdbool.h> 36 : : #include <stddef.h> 37 : : 38 : : #include "libelfP.h" 39 : : 40 : : 41 : : static void * 42 : 6 : get_zdata (Elf_Scn *strscn) 43 : : { 44 : 6 : size_t zsize, zalign; 45 : 6 : void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign); 46 [ + - ]: 6 : if (zdata == NULL) 47 : : return NULL; 48 : : 49 : 6 : strscn->zdata_base = zdata; 50 : 6 : strscn->zdata_size = zsize; 51 : 6 : strscn->zdata_align = zalign; 52 : : 53 : 6 : return zdata; 54 : : } 55 : : 56 : 8006407 : static bool validate_str (const char *str, size_t from, size_t to) 57 : : { 58 : : #if HAVE_DECL_MEMRCHR 59 : 8006407 : return memrchr (&str[from], '\0', to - from) != NULL; 60 : : #else 61 : : do { 62 : : if (to <= from) 63 : : return false; 64 : : 65 : : to--; 66 : : } while (str[to]); 67 : : 68 : : return true; 69 : : #endif 70 : : } 71 : : 72 : : char * 73 : 8006418 : elf_strptr (Elf *elf, size_t idx, size_t offset) 74 : : { 75 [ + - ]: 8006418 : if (elf == NULL) 76 : : return NULL; 77 : : 78 [ - + ]: 8006418 : if (elf->kind != ELF_K_ELF) 79 : : { 80 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE); 81 : 0 : return NULL; 82 : : } 83 : : 84 : 8006418 : rwlock_rdlock (elf->lock); 85 : : 86 : 8006418 : char *result = NULL; 87 : 8006418 : Elf_Scn *strscn; 88 : : 89 : : /* Find the section in the list. */ 90 : 8006418 : Elf_ScnList *runp = (elf->class == ELFCLASS32 91 : : || (offsetof (struct Elf, state.elf32.scns) 92 : : == offsetof (struct Elf, state.elf64.scns)) 93 : : ? &elf->state.elf32.scns : &elf->state.elf64.scns); 94 : 8089620 : while (1) 95 : : { 96 [ + + ]: 8089620 : if (idx < runp->max) 97 : : { 98 [ + - ]: 8006418 : if (idx < runp->cnt) 99 : 8006418 : strscn = &runp->data[idx]; 100 : : else 101 : : { 102 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 103 : 0 : goto out; 104 : : } 105 : 8006418 : break; 106 : : } 107 : : 108 : 83202 : idx -= runp->max; 109 : : 110 : 83202 : runp = runp->next; 111 [ + - ]: 83202 : if (runp == NULL) 112 : : { 113 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 114 : 0 : goto out; 115 : : } 116 : : } 117 : : 118 : 8006418 : size_t sh_size = 0; 119 [ + + ]: 8006418 : if (elf->class == ELFCLASS32) 120 : : { 121 [ + + ]: 3143868 : Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn); 122 [ + - + + ]: 3143868 : if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB)) 123 : : { 124 : : /* This is no string section. */ 125 : 5 : __libelf_seterrno (ELF_E_INVALID_SECTION); 126 : 5 : goto out; 127 : : } 128 : : 129 [ + + ]: 3143863 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0) 130 : 3143823 : sh_size = shdr->sh_size; 131 : : else 132 : : { 133 [ + + - + ]: 40 : if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL) 134 : 0 : goto out; 135 : 40 : sh_size = strscn->zdata_size; 136 : : } 137 : : 138 [ + + ]: 3143863 : if (unlikely (offset >= sh_size)) 139 : : { 140 : : /* The given offset is too big, it is beyond this section. */ 141 : 3 : __libelf_seterrno (ELF_E_OFFSET_RANGE); 142 : 3 : goto out; 143 : : } 144 : : } 145 : : else 146 : : { 147 [ + + ]: 4862550 : Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn); 148 [ + - - + ]: 4862550 : if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB)) 149 : : { 150 : : /* This is no string section. */ 151 : 0 : __libelf_seterrno (ELF_E_INVALID_SECTION); 152 : 0 : goto out; 153 : : } 154 : : 155 [ + + ]: 4862550 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0) 156 : 4862513 : sh_size = shdr->sh_size; 157 : : else 158 : : { 159 [ + + - + ]: 37 : if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL) 160 : 0 : goto out; 161 : 37 : sh_size = strscn->zdata_size; 162 : : } 163 : : 164 [ + + ]: 4862550 : if (unlikely (offset >= sh_size)) 165 : : { 166 : : /* The given offset is too big, it is beyond this section. */ 167 : 3 : __libelf_seterrno (ELF_E_OFFSET_RANGE); 168 : 3 : goto out; 169 : : } 170 : : } 171 : : 172 [ + + + + ]: 8006407 : if (strscn->rawdata_base == NULL && ! strscn->data_read) 173 : : { 174 : 2320 : rwlock_unlock (elf->lock); 175 : 2320 : rwlock_wrlock (elf->lock); 176 : 2320 : if (strscn->rawdata_base == NULL && ! strscn->data_read 177 : : /* Read the section data. */ 178 [ - + ]: 2320 : && __libelf_set_rawdata_wrlock (strscn) != 0) 179 : 0 : goto out; 180 : : } 181 : : 182 [ + + ]: 8006407 : if (unlikely (strscn->zdata_base != NULL)) 183 : : { 184 : : /* Make sure the string is NUL terminated. Start from the end, 185 : : which very likely is a NUL char. */ 186 [ - + ]: 27598 : if (likely (validate_str (strscn->zdata_base, offset, sh_size))) 187 : : result = &strscn->zdata_base[offset]; 188 : : else 189 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 190 : : } 191 [ + + ]: 7978809 : else if (likely (strscn->data_list_rear == NULL)) 192 : : { 193 : : // XXX The above is currently correct since elf_newdata will 194 : : // make sure to convert the rawdata into the datalist if 195 : : // necessary. But it would be more efficient to keep the rawdata 196 : : // unconverted and only then iterate over the rest of the (newly 197 : : // added data) list. Note that when the ELF file is mmapped 198 : : // rawdata_base can be set while rawdata.d hasn't been 199 : : // initialized yet (when data_read is zero). So we cannot just 200 : : // look at the rawdata.d.d_size. 201 : : 202 : : /* Make sure the string is NUL terminated. Start from the end, 203 : : which very likely is a NUL char. */ 204 [ - + ]: 7877941 : if (likely (validate_str (strscn->rawdata_base, offset, sh_size))) 205 : : result = &strscn->rawdata_base[offset]; 206 : : else 207 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 208 : : } 209 : : else 210 : : { 211 : : /* This is a file which is currently created. Use the list of 212 : : data blocks. */ 213 : 100868 : struct Elf_Data_List *dl = &strscn->data_list; 214 [ + - ]: 101084 : while (dl != NULL) 215 : : { 216 [ + - ]: 101084 : if (offset >= (size_t) dl->data.d.d_off 217 [ + + ]: 101084 : && offset < dl->data.d.d_off + dl->data.d.d_size) 218 : : { 219 : : /* Make sure the string is NUL terminated. Start from 220 : : the end, which very likely is a NUL char. */ 221 [ - + ]: 100868 : if (likely (validate_str ((char *) dl->data.d.d_buf, 222 : : offset - dl->data.d.d_off, 223 : : dl->data.d.d_size))) 224 : : result = ((char *) dl->data.d.d_buf 225 : : + (offset - dl->data.d.d_off)); 226 : : else 227 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 228 : : break; 229 : : } 230 : : 231 : 216 : dl = dl->next; 232 : : } 233 : : } 234 : : 235 : 0 : out: 236 : : rwlock_unlock (elf->lock); 237 : : 238 : : return result; 239 : : } 240 : : INTDEF(elf_strptr)