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 (at) 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 get_zdata (Elf_Scn *strscn) 43 { 44 size_t zsize, zalign; 45 void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign); 46 if (zdata == NULL) 47 return NULL; 48 49 strscn->zdata_base = zdata; 50 strscn->zdata_size = zsize; 51 strscn->zdata_align = zalign; 52 53 return zdata; 54 } 55 56 static bool validate_str (const char *str, size_t from, size_t to) 57 { 58 #if HAVE_DECL_MEMRCHR 59 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 elf_strptr (Elf *elf, size_t idx, size_t offset) 74 { 75 if (elf == NULL) 76 return NULL; 77 78 if (elf->kind != ELF_K_ELF) 79 { 80 __libelf_seterrno (ELF_E_INVALID_HANDLE); 81 return NULL; 82 } 83 84 rwlock_rdlock (elf->lock); 85 86 char *result = NULL; 87 Elf_Scn *strscn; 88 89 /* Find the section in the list. */ 90 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 while (1) 95 { 96 if (idx < runp->max) 97 { 98 if (idx < runp->cnt) 99 strscn = &runp->data[idx]; 100 else 101 { 102 __libelf_seterrno (ELF_E_INVALID_INDEX); 103 goto out; 104 } 105 break; 106 } 107 108 idx -= runp->max; 109 110 runp = runp->next; 111 if (runp == NULL) 112 { 113 __libelf_seterrno (ELF_E_INVALID_INDEX); 114 goto out; 115 } 116 } 117 118 size_t sh_size = 0; 119 if (elf->class == ELFCLASS32) 120 { 121 Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn); 122 if (unlikely (shdr->sh_type != SHT_STRTAB)) 123 { 124 /* This is no string section. */ 125 __libelf_seterrno (ELF_E_INVALID_SECTION); 126 goto out; 127 } 128 129 if ((shdr->sh_flags & SHF_COMPRESSED) == 0) 130 sh_size = shdr->sh_size; 131 else 132 { 133 if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL) 134 goto out; 135 sh_size = strscn->zdata_size; 136 } 137 138 if (unlikely (offset >= sh_size)) 139 { 140 /* The given offset is too big, it is beyond this section. */ 141 __libelf_seterrno (ELF_E_OFFSET_RANGE); 142 goto out; 143 } 144 } 145 else 146 { 147 Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn); 148 if (unlikely (shdr->sh_type != SHT_STRTAB)) 149 { 150 /* This is no string section. */ 151 __libelf_seterrno (ELF_E_INVALID_SECTION); 152 goto out; 153 } 154 155 if ((shdr->sh_flags & SHF_COMPRESSED) == 0) 156 sh_size = shdr->sh_size; 157 else 158 { 159 if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL) 160 goto out; 161 sh_size = strscn->zdata_size; 162 } 163 164 if (unlikely (offset >= sh_size)) 165 { 166 /* The given offset is too big, it is beyond this section. */ 167 __libelf_seterrno (ELF_E_OFFSET_RANGE); 168 goto out; 169 } 170 } 171 172 if (strscn->rawdata_base == NULL && ! strscn->data_read) 173 { 174 rwlock_unlock (elf->lock); 175 rwlock_wrlock (elf->lock); 176 if (strscn->rawdata_base == NULL && ! strscn->data_read 177 /* Read the section data. */ 178 && __libelf_set_rawdata_wrlock (strscn) != 0) 179 goto out; 180 } 181 182 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 if (likely (validate_str (strscn->zdata_base, offset, sh_size))) 187 result = &strscn->zdata_base[offset]; 188 else 189 __libelf_seterrno (ELF_E_INVALID_INDEX); 190 } 191 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 if (likely (validate_str (strscn->rawdata_base, offset, sh_size))) 205 result = &strscn->rawdata_base[offset]; 206 else 207 __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 struct Elf_Data_List *dl = &strscn->data_list; 214 while (dl != NULL) 215 { 216 if (offset >= (size_t) dl->data.d.d_off 217 && 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 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 __libelf_seterrno (ELF_E_INVALID_INDEX); 228 break; 229 } 230 231 dl = dl->next; 232 } 233 } 234 235 out: 236 rwlock_unlock (elf->lock); 237 238 return result; 239 } 240 INTDEF(elf_strptr) 241