xref: /netbsd-src/external/bsd/elftoolchain/dist/libelf/elf_data.c (revision 5ac3bc719ce6e70593039505b491894133237d12)
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