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 : 12 : get_zdata (Elf_Scn *strscn)
43 : : {
44 : 12 : size_t zsize, zalign;
45 : 12 : void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
46 [ + - ]: 12 : if (zdata == NULL)
47 : : return NULL;
48 : :
49 : 12 : strscn->zdata_base = zdata;
50 : 12 : strscn->zdata_size = zsize;
51 : 12 : strscn->zdata_align = zalign;
52 : :
53 : 12 : return zdata;
54 : : }
55 : :
56 : 9834255 : static bool validate_str (const char *str, size_t from, size_t to)
57 : : {
58 : : #if HAVE_DECL_MEMRCHR
59 : : // Check end first, which is likely a zero terminator, to prevent function call
60 [ - + ]: 9834255 : return ((to > 0 && str[to - 1] == '\0')
61 [ + - - - : 9834255 : || (to - from > 0 && memrchr (&str[from], '\0', to - from - 1) != NULL));
- - ]
62 : : #else
63 : : do {
64 : : if (to <= from)
65 : : return false;
66 : :
67 : : to--;
68 : : } while (str[to]);
69 : :
70 : : return true;
71 : : #endif
72 : : }
73 : :
74 : : char *
75 : 9834383 : elf_strptr (Elf *elf, size_t idx, size_t offset)
76 : : {
77 [ + - ]: 9834383 : if (elf == NULL)
78 : : return NULL;
79 : :
80 [ - + ]: 9834383 : if (elf->kind != ELF_K_ELF)
81 : : {
82 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE);
83 : 0 : return NULL;
84 : : }
85 : :
86 : 9834383 : rwlock_rdlock (elf->lock);
87 : :
88 : 9834383 : char *result = NULL;
89 : 9834383 : Elf_Scn *strscn;
90 : :
91 : : /* Find the section in the list. */
92 : 9834383 : Elf_ScnList *runp = (elf->class == ELFCLASS32
93 : : || (offsetof (struct Elf, state.elf32.scns)
94 : : == offsetof (struct Elf, state.elf64.scns))
95 : : ? &elf->state.elf32.scns : &elf->state.elf64.scns);
96 : 9932453 : while (1)
97 : : {
98 [ + + ]: 9932453 : if (idx < runp->max)
99 : : {
100 [ + - ]: 9834383 : if (idx < runp->cnt)
101 : 9834383 : strscn = &runp->data[idx];
102 : : else
103 : : {
104 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
105 : 0 : goto out;
106 : : }
107 : 9834383 : break;
108 : : }
109 : :
110 : 98070 : idx -= runp->max;
111 : :
112 : 98070 : runp = runp->next;
113 [ + - ]: 98070 : if (runp == NULL)
114 : : {
115 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
116 : 0 : goto out;
117 : : }
118 : : }
119 : :
120 : 9834383 : size_t sh_size = 0;
121 [ + + ]: 9834383 : if (elf->class == ELFCLASS32)
122 : : {
123 [ + + ]: 4478466 : Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
124 [ + - + + ]: 4478466 : if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
125 : : {
126 : : /* This is no string section. */
127 : 92 : __libelf_seterrno (ELF_E_INVALID_SECTION);
128 : 92 : goto out;
129 : : }
130 : :
131 [ + + ]: 4478374 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
132 : 4478294 : sh_size = shdr->sh_size;
133 : : else
134 : : {
135 [ + + - + ]: 80 : if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
136 : 0 : goto out;
137 : 80 : sh_size = strscn->zdata_size;
138 : : }
139 : :
140 [ + + ]: 4478374 : if (unlikely (offset >= sh_size))
141 : : {
142 : : /* The given offset is too big, it is beyond this section. */
143 : 6 : __libelf_seterrno (ELF_E_OFFSET_RANGE);
144 : 6 : goto out;
145 : : }
146 : : }
147 : : else
148 : : {
149 [ + + ]: 5355917 : Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
150 [ + - - + ]: 5355917 : if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
151 : : {
152 : : /* This is no string section. */
153 : 0 : __libelf_seterrno (ELF_E_INVALID_SECTION);
154 : 0 : goto out;
155 : : }
156 : :
157 [ + + ]: 5355917 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
158 : 5355843 : sh_size = shdr->sh_size;
159 : : else
160 : : {
161 [ + + - + ]: 74 : if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
162 : 0 : goto out;
163 : 74 : sh_size = strscn->zdata_size;
164 : : }
165 : :
166 [ + + ]: 5355917 : if (unlikely (offset >= sh_size))
167 : : {
168 : : /* The given offset is too big, it is beyond this section. */
169 : 6 : __libelf_seterrno (ELF_E_OFFSET_RANGE);
170 : 6 : goto out;
171 : : }
172 : : }
173 : :
174 [ + + + + ]: 9834279 : if (strscn->rawdata_base == NULL && ! strscn->data_read)
175 : : {
176 : 5546 : rwlock_unlock (elf->lock);
177 : 5546 : rwlock_wrlock (elf->lock);
178 : 5546 : if (strscn->rawdata_base == NULL && ! strscn->data_read
179 : : /* Read the section data. */
180 [ - + ]: 5546 : && __libelf_set_rawdata_wrlock (strscn) != 0)
181 : 0 : goto out;
182 : : }
183 : :
184 [ + + ]: 9834279 : if (unlikely (strscn->zdata_base != NULL))
185 : : {
186 : : /* Make sure the string is NUL terminated. Start from the end,
187 : : which very likely is a NUL char. */
188 [ + - ]: 39106 : if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
189 : 39106 : result = &strscn->zdata_base[offset];
190 : : else
191 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
192 : : }
193 [ + + ]: 9795173 : else if (likely (strscn->data_list_rear == NULL))
194 : : {
195 : : // XXX The above is currently correct since elf_newdata will
196 : : // make sure to convert the rawdata into the datalist if
197 : : // necessary. But it would be more efficient to keep the rawdata
198 : : // unconverted and only then iterate over the rest of the (newly
199 : : // added data) list. Note that when the ELF file is mmapped
200 : : // rawdata_base can be set while rawdata.d hasn't been
201 : : // initialized yet (when data_read is zero). So we cannot just
202 : : // look at the rawdata.d.d_size.
203 : :
204 : : /* Make sure the string is NUL terminated. Start from the end,
205 : : which very likely is a NUL char. */
206 [ + - ]: 9661201 : if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
207 : 9661201 : result = &strscn->rawdata_base[offset];
208 : : else
209 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
210 : : }
211 : : else
212 : : {
213 : : /* This is a file which is currently created. Use the list of
214 : : data blocks. */
215 : 133972 : struct Elf_Data_List *dl = &strscn->data_list;
216 [ + - ]: 134404 : while (dl != NULL)
217 : : {
218 [ + - ]: 134404 : if (offset >= (size_t) dl->data.d.d_off
219 [ + + ]: 134404 : && offset < dl->data.d.d_off + dl->data.d.d_size)
220 : : {
221 : : /* Make sure the string is NUL terminated. Start from
222 : : the end, which very likely is a NUL char. */
223 [ + - ]: 133972 : if (likely (validate_str ((char *) dl->data.d.d_buf,
224 : : offset - dl->data.d.d_off,
225 : : dl->data.d.d_size)))
226 : 133972 : result = ((char *) dl->data.d.d_buf
227 : : + (offset - dl->data.d.d_off));
228 : : else
229 : 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
230 : : break;
231 : : }
232 : :
233 : 432 : dl = dl->next;
234 : : }
235 : : }
236 : :
237 : 0 : out:
238 : : rwlock_unlock (elf->lock);
239 : :
240 : : return result;
241 : : }
242 : : INTDEF(elf_strptr)
|