1 /* $NetBSD: elf_data.c,v 1.5 2024/03/03 17:37:33 christos 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 <sys/cdefs.h>
34
35 #include <assert.h>
36 #include <errno.h>
37 #include <libelf.h>
38 #include <stdint.h>
39 #include <stdlib.h>
40
41 #include "_libelf.h"
42
43 __RCSID("$NetBSD: elf_data.c,v 1.5 2024/03/03 17:37:33 christos Exp $");
44 ELFTC_VCSID("Id: elf_data.c 3977 2022-05-01 06:45:34Z jkoshy");
45
46 Elf_Data *
elf_getdata(Elf_Scn * s,Elf_Data * ed)47 elf_getdata(Elf_Scn *s, Elf_Data *ed)
48 {
49 Elf *e;
50 unsigned int sh_type;
51 int elfclass, elftype;
52 size_t count, fsz, msz;
53 struct _Libelf_Data *d;
54 uint64_t sh_align, sh_offset, sh_size, raw_size;
55 _libelf_translator_function *xlate;
56
57 d = (struct _Libelf_Data *) ed;
58
59 if (s == NULL || (e = s->s_elf) == NULL ||
60 (d != NULL && s != d->d_scn)) {
61 LIBELF_SET_ERROR(ARGUMENT, 0);
62 return (NULL);
63 }
64
65 assert(e->e_kind == ELF_K_ELF);
66
67 if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL)
68 return (&d->d_data);
69
70 if (d != NULL)
71 return (STAILQ_NEXT(d, d_next) ?
72 &STAILQ_NEXT(d, d_next)->d_data : NULL);
73
74 if (e->e_rawfile == NULL) {
75 /*
76 * In the ELF_C_WRITE case, there is no source that
77 * can provide data for the section.
78 */
79 LIBELF_SET_ERROR(ARGUMENT, 0);
80 return (NULL);
81 }
82
83 elfclass = e->e_class;
84
85 assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
86
87 if (elfclass == ELFCLASS32) {
88 sh_type = s->s_shdr.s_shdr32.sh_type;
89 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
90 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
91 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
92 } else {
93 sh_type = s->s_shdr.s_shdr64.sh_type;
94 sh_offset = s->s_shdr.s_shdr64.sh_offset;
95 sh_size = s->s_shdr.s_shdr64.sh_size;
96 sh_align = s->s_shdr.s_shdr64.sh_addralign;
97 }
98
99 if (sh_type == SHT_NULL) {
100 LIBELF_SET_ERROR(SECTION, 0);
101 return (NULL);
102 }
103
104 raw_size = (uint64_t) e->e_rawsize;
105 if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST ||
106 elftype > ELF_T_LAST || (sh_type != SHT_NOBITS &&
107 (sh_offset > raw_size || sh_size > raw_size - sh_offset))) {
108 LIBELF_SET_ERROR(SECTION, 0);
109 return (NULL);
110 }
111
112 if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)
113 (elftype, (size_t) 1, e->e_version)) == 0) {
114 LIBELF_SET_ERROR(UNIMPL, 0);
115 return (NULL);
116 }
117
118 if (sh_size % fsz) {
119 LIBELF_SET_ERROR(SECTION, 0);
120 return (NULL);
121 }
122
123 if (sh_size / fsz > SIZE_MAX) {
124 LIBELF_SET_ERROR(RANGE, 0);
125 return (NULL);
126 }
127
128 count = (size_t) (sh_size / fsz);
129
130 if ((msz = _libelf_msize(elftype, elfclass, e->e_version)) == 0)
131 return (NULL);
132
133 if (count > 0 && msz > SIZE_MAX / count) {
134 LIBELF_SET_ERROR(RANGE, 0);
135 return (NULL);
136 }
137
138 assert(msz > 0);
139 assert(count <= SIZE_MAX);
140 assert(msz * count <= SIZE_MAX);
141
142 if ((d = _libelf_allocate_data(s)) == NULL)
143 return (NULL);
144
145 d->d_data.d_buf = NULL;
146 d->d_data.d_off = 0;
147 d->d_data.d_align = sh_align;
148 d->d_data.d_size = msz * count;
149 d->d_data.d_type = elftype;
150 d->d_data.d_version = e->e_version;
151
152 if (sh_type == SHT_NOBITS || sh_size == 0) {
153 STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
154 return (&d->d_data);
155 }
156
157 if ((d->d_data.d_buf = malloc(msz * count)) == NULL) {
158 (void) _libelf_release_data(d);
159 LIBELF_SET_ERROR(RESOURCE, 0);
160 return (NULL);
161 }
162
163 d->d_flags |= LIBELF_F_DATA_MALLOCED;
164
165 xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass,
166 _libelf_elfmachine(e));
167 if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size,
168 e->e_rawfile + sh_offset, count,
169 e->e_byteorder != LIBELF_PRIVATE(byteorder))) {
170 _libelf_release_data(d);
171 LIBELF_SET_ERROR(DATA, 0);
172 return (NULL);
173 }
174
175 STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
176
177 return (&d->d_data);
178 }
179
180 Elf_Data *
elf_newdata(Elf_Scn * s)181 elf_newdata(Elf_Scn *s)
182 {
183 Elf *e;
184 struct _Libelf_Data *d;
185
186 if (s == NULL || (e = s->s_elf) == NULL) {
187 LIBELF_SET_ERROR(ARGUMENT, 0);
188 return (NULL);
189 }
190
191 assert(e->e_kind == ELF_K_ELF);
192
193 /*
194 * elf_newdata() has to append a data descriptor, so
195 * bring in existing section data if not already present.
196 */
197 if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data))
198 if (elf_getdata(s, NULL) == NULL)
199 return (NULL);
200
201 if ((d = _libelf_allocate_data(s)) == NULL)
202 return (NULL);
203
204 STAILQ_INSERT_TAIL(&s->s_data, d, d_next);
205
206 d->d_data.d_align = 1;
207 d->d_data.d_buf = NULL;
208 d->d_data.d_off = (uint64_t) ~0;
209 d->d_data.d_size = 0;
210 d->d_data.d_type = ELF_T_BYTE;
211 d->d_data.d_version = LIBELF_PRIVATE(version);
212
213 (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY);
214
215 return (&d->d_data);
216 }
217
218 /*
219 * Retrieve a data descriptor for raw (untranslated) data for section
220 * `s'.
221 */
222
223 Elf_Data *
elf_rawdata(Elf_Scn * s,Elf_Data * ed)224 elf_rawdata(Elf_Scn *s, Elf_Data *ed)
225 {
226 Elf *e;
227 int elf_class;
228 uint32_t sh_type;
229 struct _Libelf_Data *d;
230 uint64_t sh_align, sh_offset, sh_size, raw_size;
231
232 if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) {
233 LIBELF_SET_ERROR(ARGUMENT, 0);
234 return (NULL);
235 }
236
237 assert(e->e_kind == ELF_K_ELF);
238
239 d = (struct _Libelf_Data *) ed;
240
241 if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL)
242 return (&d->d_data);
243
244 if (d != NULL)
245 return (&STAILQ_NEXT(d, d_next)->d_data);
246
247 elf_class = e->e_class;
248
249 assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64);
250
251 if (elf_class == ELFCLASS32) {
252 sh_type = s->s_shdr.s_shdr32.sh_type;
253 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
254 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size;
255 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
256 } else {
257 sh_type = s->s_shdr.s_shdr64.sh_type;
258 sh_offset = s->s_shdr.s_shdr64.sh_offset;
259 sh_size = s->s_shdr.s_shdr64.sh_size;
260 sh_align = s->s_shdr.s_shdr64.sh_addralign;
261 }
262
263 if (sh_type == SHT_NULL) {
264 LIBELF_SET_ERROR(SECTION, 0);
265 return (NULL);
266 }
267
268 raw_size = (uint64_t) e->e_rawsize;
269 if (sh_type != SHT_NOBITS &&
270 (sh_offset > raw_size || sh_size > raw_size - sh_offset)) {
271 LIBELF_SET_ERROR(SECTION, 0);
272 return (NULL);
273 }
274
275 if ((d = _libelf_allocate_data(s)) == NULL)
276 return (NULL);
277
278 d->d_data.d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL :
279 e->e_rawfile + sh_offset;
280 d->d_data.d_off = 0;
281 d->d_data.d_align = sh_align;
282 d->d_data.d_size = sh_size;
283 d->d_data.d_type = ELF_T_BYTE;
284 d->d_data.d_version = e->e_version;
285
286 STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next);
287
288 return (&d->d_data);
289 }
290