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 $"); 44ELFTC_VCSID("Id: elf_data.c 3977 2022-05-01 06:45:34Z jkoshy"); 45 46Elf_Data * 47elf_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 180Elf_Data * 181elf_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 223Elf_Data * 224elf_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