Home | History | Annotate | Line # | Download | only in libelf
      1 /*	$NetBSD: elf_data.c,v 1.6 2025/12/25 18:58:12 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 <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 ELFTC_VCSID("Id: elf_data.c 4231 2025-10-13 15:24:01Z jkoshy");
     44 
     45 __RCSID("$NetBSD: elf_data.c,v 1.6 2025/12/25 18:58:12 jkoshy Exp $");
     46 
     47 Elf_Data *
     48 elf_getdata(Elf_Scn *s, Elf_Data *ed)
     49 {
     50 	Elf *e;
     51 	unsigned int elfclass, sh_type;
     52 	int elftype;
     53 	size_t count, fsz, msz;
     54 	struct _Libelf_Data *d;
     55 	uint64_t sh_align, sh_offset, sh_size, raw_size;
     56 	_libelf_translator_function *xlate;
     57 
     58 	d = (struct _Libelf_Data *) ed;
     59 
     60 	if (s == NULL || (e = s->s_elf) == NULL ||
     61 	    (d != NULL && s != d->d_scn)) {
     62 		LIBELF_SET_ERROR(ARGUMENT, 0);
     63 		return (NULL);
     64 	}
     65 
     66 	assert(e->e_kind == ELF_K_ELF);
     67 
     68 	if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL)
     69 		return (&d->d_data);
     70 
     71 	if (d != NULL)
     72 		return (STAILQ_NEXT(d, d_next) ?
     73 		    &STAILQ_NEXT(d, d_next)->d_data : NULL);
     74 
     75 	if (e->e_rawfile == NULL) {
     76 		/*
     77 		 * In the ELF_C_WRITE case, there is no source that
     78 		 * can provide data for the section.
     79 		 */
     80 		LIBELF_SET_ERROR(ARGUMENT, 0);
     81 		return (NULL);
     82 	}
     83 
     84 	elfclass = e->e_class;
     85 
     86 	assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64);
     87 
     88 	if (elfclass == ELFCLASS32) {
     89 		sh_type   = s->s_shdr.s_shdr32.sh_type;
     90 		sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset;
     91 		sh_size   = (uint64_t) s->s_shdr.s_shdr32.sh_size;
     92 		sh_align  = (uint64_t) s->s_shdr.s_shdr32.sh_addralign;
     93 	} else {
     94 		sh_type   = s->s_shdr.s_shdr64.sh_type;
     95 		sh_offset = s->s_shdr.s_shdr64.sh_offset;
     96 		sh_size   = s->s_shdr.s_shdr64.sh_size;
     97 		sh_align  = s->s_shdr.s_shdr64.sh_addralign;
     98 	}
     99 
    100 	if (sh_type == SHT_NULL) {
    101 		LIBELF_SET_ERROR(SECTION, 0);
    102 		return (NULL);
    103 	}
    104 
    105 	raw_size = (uint64_t) e->e_rawsize;
    106 	if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST ||
    107 	    elftype > ELF_T_LAST || (sh_type != SHT_NOBITS &&
    108 	    (sh_offset > raw_size || sh_size > raw_size - sh_offset))) {
    109 		LIBELF_SET_ERROR(SECTION, 0);
    110 		return (NULL);
    111 	}
    112 
    113 	if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize)
    114             (elftype, (size_t) 1, e->e_version)) == 0) {
    115 		LIBELF_SET_ERROR(UNIMPL, 0);
    116 		return (NULL);
    117 	}
    118 
    119 	if (sh_size % fsz) {
    120 		LIBELF_SET_ERROR(SECTION, 0);
    121 		return (NULL);
    122 	}
    123 
    124 	if (sh_size / fsz > SIZE_MAX) {
    125 		LIBELF_SET_ERROR(RANGE, 0);
    126 		return (NULL);
    127 	}
    128 
    129 	count = (size_t) (sh_size / fsz);
    130 
    131 	if ((msz = _libelf_msize(elftype, elfclass, e->e_version)) == 0)
    132 		return (NULL);
    133 
    134 	if (count > 0 && msz > SIZE_MAX / count) {
    135 		LIBELF_SET_ERROR(RANGE, 0);
    136 		return (NULL);
    137 	}
    138 
    139 	assert(msz > 0);
    140 	assert(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 *
    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 *
    224 elf_rawdata(Elf_Scn *s, Elf_Data *ed)
    225 {
    226 	Elf *e;
    227 	uint32_t sh_type;
    228 	unsigned int elf_class;
    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