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 : 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 6015163 : 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 6015174 : elf_strptr (Elf *elf, size_t idx, size_t offset)
74 : {
75 6015174 : if (elf == NULL)
76 : return NULL;
77 :
78 6015174 : if (elf->kind != ELF_K_ELF)
79 : {
80 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE);
81 0 : return NULL;
82 : }
83 :
84 : rwlock_rdlock (elf->lock);
85 :
86 6015174 : char *result = NULL;
87 : Elf_Scn *strscn;
88 :
89 : /* Find the section in the list. */
90 6015174 : 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 : while (1)
95 : {
96 6079725 : if (idx < runp->max)
97 : {
98 6015174 : if (idx < runp->cnt)
99 6015174 : strscn = &runp->data[idx];
100 : else
101 : {
102 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
103 0 : goto out;
104 : }
105 : break;
106 : }
107 :
108 64551 : idx -= runp->max;
109 :
110 64551 : runp = runp->next;
111 64551 : if (runp == NULL)
112 : {
113 0 : __libelf_seterrno (ELF_E_INVALID_INDEX);
114 0 : goto out;
115 : }
116 : }
117 :
118 6015174 : size_t sh_size = 0;
119 6015174 : if (elf->class == ELFCLASS32)
120 : {
121 2993747 : Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
122 2993747 : if (unlikely (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 2993742 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
130 2993702 : 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 2993742 : 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 3021427 : Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
148 3021427 : if (unlikely (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 3021427 : if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
156 3021390 : 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 3021427 : 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 6015163 : if (strscn->rawdata_base == NULL && ! strscn->data_read)
173 : {
174 : rwlock_unlock (elf->lock);
175 : rwlock_wrlock (elf->lock);
176 : if (strscn->rawdata_base == NULL && ! strscn->data_read
177 : /* Read the section data. */
178 1522 : && __libelf_set_rawdata_wrlock (strscn) != 0)
179 : goto out;
180 : }
181 :
182 6015163 : 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 22698 : 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 6003814 : 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 11803498 : 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 102065 : struct Elf_Data_List *dl = &strscn->data_list;
214 204346 : while (dl != NULL)
215 : {
216 102281 : if (offset >= (size_t) dl->data.d.d_off
217 102281 : && 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 204130 : 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)
|