1 /* $NetBSD: elf_data.c,v 1.4 2022/05/01 19:41:35 jkoshy Exp $ */
2
3 /*-
4 * Copyright (c) 2006,2008,2011 Joseph Koshy
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #if HAVE_NBTOOL_CONFIG_H
30 # include "nbtool_config.h"
31 #endif
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <libelf.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38
39 #include "_libelf.h"
40
41 __RCSID("$NetBSD: elf_data.c,v 1.4 2022/05/01 19:41:35 jkoshy Exp $");
42 ELFTC_VCSID("Id: elf_data.c 3258 2015-11-20 18:59:43Z emaste");
43
44 Elf_Data *
elf_getdata(Elf_Scn * s,Elf_Data * ed)45 elf_getdata(Elf_Scn *s, Elf_Data *ed)
46 {
47 Elf *e;
48 unsigned int sh_type;
49 int elfclass, elftype;
50 size_t count, fsz, msz;
51 struct _Libelf_Data *d;
52 uint64_t sh_align, sh_offset, sh_size;
53 int (*xlate)(unsigned char *_d, size_t _dsz, unsigned char *_s,
54 size_t _c, int _swap);
55
56 d = (struct _Libelf_Data *) ed;
57
58 if (s == NULL || (e = s->s_elf) == NULL ||
59 (d != NULL && s != d->d_scn)) {
60 LIBELF_SET_ERROR(ARGUMENT, 0);
61 return (NULL);
62 }
63
64 assert(e->e_kind == ELF_K_ELF);
65
66 if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL)
67 return (&d->d_data);
68
69 if (d != NULL)
70 return (&STAILQ_NEXT(d, d_next)->d_data);
71
72 if (e->e_rawfile == NULL) {
73 /*
74 * In the ELF_C_WRITE case, there is no source that
75 * can provide data for the section.
76 */
77 LIBELF_SET_ERROR(ARGUMENT, 0);
78 return (NULL);
79 }
80
81 elfclass = e->e_class;
82
83 assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
84
85 if (elfclass == ELFCLASS32) {
86 sh_type = s->s_shdr.s_shdr32.sh_type;
87 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
88 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
89 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
90 } else {
91 sh_type = s->s_shdr.s_shdr64.sh_type;
92 sh_offset = s->s_shdr.s_shdr64.sh_offset;
93 sh_size = s->s_shdr.s_shdr64.sh_size;
94 sh_align = s->s_shdr.s_shdr64.sh_addralign;
95 }
96
97 if (sh_type == SHT_NULL) {
98 LIBELF_SET_ERROR(SECTION, 0);
99 return (NULL);
100 }
101
102 if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST ||
103 elftype > ELF_T_LAST || (sh_type != SHT_NOBITS &&
104 sh_offset + sh_size > (uint64_t) e->e_rawsize)) {
105 LIBELF_SET_ERROR(SECTION, 0);
106 return (NULL);
107 }
108
109 if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)
110 (elftype, (size_t) 1, e->e_version)) == 0) {
111 LIBELF_SET_ERROR(UNIMPL, 0);
112 return (NULL);
113 }
114
115 if (sh_size % fsz) {
116 LIBELF_SET_ERROR(SECTION, 0);
117 return (NULL);
118 }
119
120 if (sh_size / fsz > SIZE_MAX) {
121 LIBELF_SET_ERROR(RANGE, 0);
122 return (NULL);
123 }
124
125 count = (size_t) (sh_size / fsz);
126
127 msz = _libelf_msize(elftype, elfclass, e->e_version);
128
129 if (count > 0 && msz > SIZE_MAX / count) {
130 LIBELF_SET_ERROR(RANGE, 0);
131 return (NULL);
132 }
133
134 assert(msz > 0);
135 assert(count <= SIZE_MAX);
136 assert(msz * count <= SIZE_MAX);
137
138 if ((d = _libelf_allocate_data(s)) == NULL)
139 return (NULL);
140
141 d->d_data.d_buf = NULL;
142 d->d_data.d_off = 0;
143 d->d_data.d_align = sh_align;
144 d->d_data.d_size = msz * count;
145 d->d_data.d_type = elftype;
146 d->d_data.d_version = e->e_version;
147
148 if (sh_type == SHT_NOBITS || sh_size == 0) {
149 STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
150 return (&d->d_data);
151 }
152
153 if ((d->d_data.d_buf = malloc(msz * count)) == NULL) {
154 (void) _libelf_release_data(d);
155 LIBELF_SET_ERROR(RESOURCE, 0);
156 return (NULL);
157 }
158
159 d->d_flags |= LIBELF_F_DATA_MALLOCED;
160
161 xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass);
162 if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size,
163 e->e_rawfile + sh_offset, count,
164 e->e_byteorder != _libelf_host_byteorder())) {
165 _libelf_release_data(d);
166 LIBELF_SET_ERROR(DATA, 0);
167 return (NULL);
168 }
169
170 STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
171
172 return (&d->d_data);
173 }
174
175 Elf_Data *
elf_newdata(Elf_Scn * s)176 elf_newdata(Elf_Scn *s)
177 {
178 Elf *e;
179 struct _Libelf_Data *d;
180
181 if (s == NULL || (e = s->s_elf) == NULL) {
182 LIBELF_SET_ERROR(ARGUMENT, 0);
183 return (NULL);
184 }
185
186 assert(e->e_kind == ELF_K_ELF);
187
188 /*
189 * elf_newdata() has to append a data descriptor, so
190 * bring in existing section data if not already present.
191 */
192 if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data))
193 if (elf_getdata(s, NULL) == NULL)
194 return (NULL);
195
196 if ((d = _libelf_allocate_data(s)) == NULL)
197 return (NULL);
198
199 STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
200
201 d->d_data.d_align = 1;
202 d->d_data.d_buf = NULL;
203 d->d_data.d_off = (uint64_t) ~0;
204 d->d_data.d_size = 0;
205 d->d_data.d_type = ELF_T_BYTE;
206 d->d_data.d_version = LIBELF_PRIVATE(version);
207
208 (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY);
209
210 return (&d->d_data);
211 }
212
213 /*
214 * Retrieve a data descriptor for raw (untranslated) data for section
215 * `s'.
216 */
217
218 Elf_Data *
elf_rawdata(Elf_Scn * s,Elf_Data * ed)219 elf_rawdata(Elf_Scn *s, Elf_Data *ed)
220 {
221 Elf *e;
222 int elf_class;
223 uint32_t sh_type;
224 struct _Libelf_Data *d;
225 uint64_t sh_align, sh_offset, sh_size;
226
227 if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) {
228 LIBELF_SET_ERROR(ARGUMENT, 0);
229 return (NULL);
230 }
231
232 assert(e->e_kind == ELF_K_ELF);
233
234 d = (struct _Libelf_Data *) ed;
235
236 if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL)
237 return (&d->d_data);
238
239 if (d != NULL)
240 return (&STAILQ_NEXT(d, d_next)->d_data);
241
242 elf_class = e->e_class;
243
244 assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64);
245
246 if (elf_class == ELFCLASS32) {
247 sh_type = s->s_shdr.s_shdr32.sh_type;
248 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
249 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
250 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
251 } else {
252 sh_type = s->s_shdr.s_shdr64.sh_type;
253 sh_offset = s->s_shdr.s_shdr64.sh_offset;
254 sh_size = s->s_shdr.s_shdr64.sh_size;
255 sh_align = s->s_shdr.s_shdr64.sh_addralign;
256 }
257
258 if (sh_type == SHT_NULL) {
259 LIBELF_SET_ERROR(SECTION, 0);
260 return (NULL);
261 }
262
263 if (sh_type != SHT_NOBITS &&
264 sh_offset + sh_size > (uint64_t) e->e_rawsize) {
265 LIBELF_SET_ERROR(SECTION, 0);
266 return (NULL);
267 }
268
269 if ((d = _libelf_allocate_data(s)) == NULL)
270 return (NULL);
271
272 d->d_data.d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL :
273 e->e_rawfile + sh_offset;
274 d->d_data.d_off = 0;
275 d->d_data.d_align = sh_align;
276 d->d_data.d_size = sh_size;
277 d->d_data.d_type = ELF_T_BYTE;
278 d->d_data.d_version = e->e_version;
279
280 STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next);
281
282 return (&d->d_data);
283 }
284