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