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