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