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