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 : 12032915 : elf_strptr (Elf *elf, size_t idx, size_t offset)
59 : : {
60 [ - + ]: 12032915 : if (elf == NULL)
61 : : return NULL;
62 : :
63 [ - + ]: 12032915 : if (elf->kind != ELF_K_ELF)
64 : : {
65 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE);
66 : 0 : return NULL;
67 : : }
68 : :
69 : 12032915 : rwlock_rdlock (elf->lock);
70 : :
71 : 12032915 : char *result = NULL;
72 : 12032915 : Elf_Scn *strscn;
73 : :
74 : : /* Find the section in the list. */
75 : 12032915 : 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 : 12138869 : while (1)
80 : : {
81 [ + + ]: 12138869 : if (idx < runp->max)
82 : : {
83 [ + - ]: 12032915 : if (idx < runp->cnt)
84 : 12032915 : strscn = &runp->data[idx];
85 : : else
86 : : {
87 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
88 : 0 : goto out;
89 : : }
90 : 12032915 : break;
91 : : }
92 : :
93 : 105954 : idx -= runp->max;
94 : :
95 : 105954 : runp = runp->next;
96 [ + - ]: 105954 : if (runp == NULL)
97 : : {
98 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
99 : 0 : goto out;
100 : : }
101 : : }
102 : :
103 : 12032915 : size_t sh_size = 0;
104 [ + + ]: 12032915 : if (elf->class == ELFCLASS32)
105 : : {
106 [ + + ]: 4479162 : Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
107 [ + - + + ]: 4479162 : 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 [ + + ]: 4479070 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
115 : 4478990 : 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 [ + + ]: 4479070 : 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 [ + + ]: 7553753 : Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
133 [ + - - + ]: 7553753 : 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 [ + + ]: 7553753 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
141 : 7553679 : 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 [ + + ]: 7553753 : 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 [ + + + + ]: 12032811 : if (strscn->rawdata_base == NULL && ! strscn->data_read)
158 : : {
159 : 5632 : rwlock_unlock (elf->lock);
160 : 5632 : rwlock_wrlock (elf->lock);
161 : 5632 : if (strscn->rawdata_base == NULL && ! strscn->data_read
162 : : /* Read the section data. */
163 [ - + ]: 5632 : && __libelf_set_rawdata_wrlock (strscn) != 0)
164 : 0 : goto out;
165 : : }
166 : :
167 [ + + ]: 12032811 : 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 [ + - ]: 38538 : if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
172 : 38538 : result = &strscn->zdata_base[offset];
173 : : else
174 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
175 : : }
176 [ + + ]: 11994273 : 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 [ - + ]: 11852189 : if (unlikely (strscn->rawdata_base == NULL))
191 : 0 : __libelf_seterrno (ELF_E_INVALID_SECTION);
192 [ + - ]: 11852189 : else if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
193 : 11852189 : 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 : 142084 : struct Elf_Data_List *dl = &strscn->data_list;
202 [ + - ]: 142516 : while (dl != NULL)
203 : : {
204 [ + - ]: 142516 : if (offset >= (size_t) dl->data.d.d_off
205 [ + + ]: 142516 : && 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 [ + - ]: 142084 : if (likely (validate_str ((char *) dl->data.d.d_buf,
210 : : offset - dl->data.d.d_off,
211 : : dl->data.d.d_size)))
212 : 142084 : 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)
|