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