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 : 12 : get_zdata (Elf_Scn *strscn) 43 : : { 44 : 12 : size_t zsize, zalign; 45 : 12 : void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign); 46 [ + - ]: 12 : if (zdata == NULL) 47 : : return NULL; 48 : : 49 : 12 : strscn->zdata_base = zdata; 50 : 12 : strscn->zdata_size = zsize; 51 : 12 : strscn->zdata_align = zalign; 52 : : 53 : 12 : return zdata; 54 : : } 55 : : 56 : 9647444 : static bool validate_str (const char *str, size_t from, size_t to) 57 : : { 58 : : #if HAVE_DECL_MEMRCHR 59 : : // Check end first, which is likely a zero terminator, to prevent function call 60 [ - + ]: 9647444 : return ((to > 0 && str[to - 1] == '\0') 61 [ + - - - : 9647444 : || (to - from > 0 && memrchr (&str[from], '\0', to - from - 1) != NULL)); - - ] 62 : : #else 63 : : do { 64 : : if (to <= from) 65 : : return false; 66 : : 67 : : to--; 68 : : } while (str[to]); 69 : : 70 : : return true; 71 : : #endif 72 : : } 73 : : 74 : : char * 75 : 9647569 : elf_strptr (Elf *elf, size_t idx, size_t offset) 76 : : { 77 [ - + ]: 9647569 : if (elf == NULL) 78 : : return NULL; 79 : : 80 [ - + ]: 9647569 : if (elf->kind != ELF_K_ELF) 81 : : { 82 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE); 83 : 0 : return NULL; 84 : : } 85 : : 86 : 9647569 : rwlock_rdlock (elf->lock); 87 : : 88 : 9647569 : char *result = NULL; 89 : 9647569 : Elf_Scn *strscn; 90 : : 91 : : /* Find the section in the list. */ 92 : 9647569 : Elf_ScnList *runp = (elf->class == ELFCLASS32 93 : : || (offsetof (struct Elf, state.elf32.scns) 94 : : == offsetof (struct Elf, state.elf64.scns)) 95 : : ? &elf->state.elf32.scns : &elf->state.elf64.scns); 96 : 9751591 : while (1) 97 : : { 98 [ + + ]: 9751591 : if (idx < runp->max) 99 : : { 100 [ + - ]: 9647569 : if (idx < runp->cnt) 101 : 9647569 : strscn = &runp->data[idx]; 102 : : else 103 : : { 104 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 105 : 0 : goto out; 106 : : } 107 : 9647569 : break; 108 : : } 109 : : 110 : 104022 : idx -= runp->max; 111 : : 112 : 104022 : runp = runp->next; 113 [ + - ]: 104022 : if (runp == NULL) 114 : : { 115 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 116 : 0 : goto out; 117 : : } 118 : : } 119 : : 120 : 9647569 : size_t sh_size = 0; 121 [ + + ]: 9647569 : if (elf->class == ELFCLASS32) 122 : : { 123 [ + + ]: 4478728 : Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn); 124 [ + - + + ]: 4478728 : if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB)) 125 : : { 126 : : /* This is no string section. */ 127 : 92 : __libelf_seterrno (ELF_E_INVALID_SECTION); 128 : 92 : goto out; 129 : : } 130 : : 131 [ + + ]: 4478636 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0) 132 : 4478556 : sh_size = shdr->sh_size; 133 : : else 134 : : { 135 [ + + - + ]: 80 : if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL) 136 : 0 : goto out; 137 : 80 : sh_size = strscn->zdata_size; 138 : : } 139 : : 140 [ + + ]: 4478636 : if (unlikely (offset >= sh_size)) 141 : : { 142 : : /* The given offset is too big, it is beyond this section. */ 143 : 6 : __libelf_seterrno (ELF_E_OFFSET_RANGE); 144 : 6 : goto out; 145 : : } 146 : : } 147 : : else 148 : : { 149 [ + + ]: 5168841 : Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn); 150 [ + - - + ]: 5168841 : if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB)) 151 : : { 152 : : /* This is no string section. */ 153 : 0 : __libelf_seterrno (ELF_E_INVALID_SECTION); 154 : 0 : goto out; 155 : : } 156 : : 157 [ + + ]: 5168841 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0) 158 : 5168767 : sh_size = shdr->sh_size; 159 : : else 160 : : { 161 [ + + - + ]: 74 : if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL) 162 : 0 : goto out; 163 : 74 : sh_size = strscn->zdata_size; 164 : : } 165 : : 166 [ + + ]: 5168841 : if (unlikely (offset >= sh_size)) 167 : : { 168 : : /* The given offset is too big, it is beyond this section. */ 169 : 6 : __libelf_seterrno (ELF_E_OFFSET_RANGE); 170 : 6 : goto out; 171 : : } 172 : : } 173 : : 174 [ + + + + ]: 9647465 : if (strscn->rawdata_base == NULL && ! strscn->data_read) 175 : : { 176 : 5240 : rwlock_unlock (elf->lock); 177 : 5240 : rwlock_wrlock (elf->lock); 178 : 5240 : if (strscn->rawdata_base == NULL && ! strscn->data_read 179 : : /* Read the section data. */ 180 [ - + ]: 5240 : && __libelf_set_rawdata_wrlock (strscn) != 0) 181 : 0 : goto out; 182 : : } 183 : : 184 [ + + ]: 9647465 : if (unlikely (strscn->zdata_base != NULL)) 185 : : { 186 : : /* Make sure the string is NUL terminated. Start from the end, 187 : : which very likely is a NUL char. */ 188 [ + - ]: 35100 : if (likely (validate_str (strscn->zdata_base, offset, sh_size))) 189 : 35100 : result = &strscn->zdata_base[offset]; 190 : : else 191 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 192 : : } 193 [ + + ]: 9612365 : else if (likely (strscn->data_list_rear == NULL)) 194 : : { 195 : : // XXX The above is currently correct since elf_newdata will 196 : : // make sure to convert the rawdata into the datalist if 197 : : // necessary. But it would be more efficient to keep the rawdata 198 : : // unconverted and only then iterate over the rest of the (newly 199 : : // added data) list. Note that when the ELF file is mmapped 200 : : // rawdata_base can be set while rawdata.d hasn't been 201 : : // initialized yet (when data_read is zero). So we cannot just 202 : : // look at the rawdata.d.d_size. 203 : : 204 : : /* Make sure the string is NUL terminated. Start from the end, 205 : : which very likely is a NUL char. */ 206 [ + - ]: 9473409 : if (likely (validate_str (strscn->rawdata_base, offset, sh_size))) 207 : 9473409 : result = &strscn->rawdata_base[offset]; 208 : : else 209 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 210 : : } 211 : : else 212 : : { 213 : : /* This is a file which is currently created. Use the list of 214 : : data blocks. */ 215 : 138956 : struct Elf_Data_List *dl = &strscn->data_list; 216 [ + - ]: 139388 : while (dl != NULL) 217 : : { 218 [ + - ]: 139388 : if (offset >= (size_t) dl->data.d.d_off 219 [ + + ]: 139388 : && offset < dl->data.d.d_off + dl->data.d.d_size) 220 : : { 221 : : /* Make sure the string is NUL terminated. Start from 222 : : the end, which very likely is a NUL char. */ 223 [ + - ]: 138956 : if (likely (validate_str ((char *) dl->data.d.d_buf, 224 : : offset - dl->data.d.d_off, 225 : : dl->data.d.d_size))) 226 : 138956 : result = ((char *) dl->data.d.d_buf 227 : : + (offset - dl->data.d.d_off)); 228 : : else 229 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX); 230 : : break; 231 : : } 232 : : 233 : 432 : dl = dl->next; 234 : : } 235 : : } 236 : : 237 : 0 : out: 238 : : rwlock_unlock (elf->lock); 239 : : 240 : : return result; 241 : : } 242 : : INTDEF(elf_strptr)