1 /* $NetBSD: elf_data.c,v 1.3 2016/02/20 02:43:42 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 <assert.h> 34 #include <errno.h> 35 #include <libelf.h> 36 #include <stdint.h> 37 #include <stdlib.h> 38 39 #include "_libelf.h" 40 41 __RCSID("$NetBSD: elf_data.c,v 1.3 2016/02/20 02:43:42 christos Exp $"); 42 ELFTC_VCSID("Id: elf_data.c 3258 2015-11-20 18:59:43Z emaste "); 43 44 Elf_Data * 45 elf_getdata(Elf_Scn *s, Elf_Data *ed) 46 { 47 Elf *e; 48 unsigned int sh_type; 49 int elfclass, elftype; 50 size_t count, fsz, msz; 51 struct _Libelf_Data *d; 52 uint64_t sh_align, sh_offset, sh_size; 53 int (*xlate)(unsigned char *_d, size_t _dsz, unsigned char *_s, 54 size_t _c, int _swap); 55 56 d = (struct _Libelf_Data *) ed; 57 58 if (s == NULL || (e = s->s_elf) == NULL || 59 (d != NULL && s != d->d_scn)) { 60 LIBELF_SET_ERROR(ARGUMENT, 0); 61 return (NULL); 62 } 63 64 assert(e->e_kind == ELF_K_ELF); 65 66 if (d == NULL && (d = STAILQ_FIRST(&s->s_data)) != NULL) 67 return (&d->d_data); 68 69 if (d != NULL) 70 return (&STAILQ_NEXT(d, d_next)->d_data); 71 72 if (e->e_rawfile == NULL) { 73 /* 74 * In the ELF_C_WRITE case, there is no source that 75 * can provide data for the section. 76 */ 77 LIBELF_SET_ERROR(ARGUMENT, 0); 78 return (NULL); 79 } 80 81 elfclass = e->e_class; 82 83 assert(elfclass == ELFCLASS32 || elfclass == ELFCLASS64); 84 85 if (elfclass == ELFCLASS32) { 86 sh_type = s->s_shdr.s_shdr32.sh_type; 87 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 88 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 89 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 90 } else { 91 sh_type = s->s_shdr.s_shdr64.sh_type; 92 sh_offset = s->s_shdr.s_shdr64.sh_offset; 93 sh_size = s->s_shdr.s_shdr64.sh_size; 94 sh_align = s->s_shdr.s_shdr64.sh_addralign; 95 } 96 97 if (sh_type == SHT_NULL) { 98 LIBELF_SET_ERROR(SECTION, 0); 99 return (NULL); 100 } 101 102 if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST || 103 elftype > ELF_T_LAST || (sh_type != SHT_NOBITS && 104 sh_offset + sh_size > (uint64_t) e->e_rawsize)) { 105 LIBELF_SET_ERROR(SECTION, 0); 106 return (NULL); 107 } 108 109 if ((fsz = (elfclass == ELFCLASS32 ? elf32_fsize : elf64_fsize) 110 (elftype, (size_t) 1, e->e_version)) == 0) { 111 LIBELF_SET_ERROR(UNIMPL, 0); 112 return (NULL); 113 } 114 115 if (sh_size % fsz) { 116 LIBELF_SET_ERROR(SECTION, 0); 117 return (NULL); 118 } 119 120 if (sh_size / fsz > SIZE_MAX) { 121 LIBELF_SET_ERROR(RANGE, 0); 122 return (NULL); 123 } 124 125 count = (size_t) (sh_size / fsz); 126 127 msz = _libelf_msize(elftype, elfclass, e->e_version); 128 129 if (count > 0 && msz > SIZE_MAX / count) { 130 LIBELF_SET_ERROR(RANGE, 0); 131 return (NULL); 132 } 133 134 assert(msz > 0); 135 assert(count <= SIZE_MAX); 136 assert(msz * count <= SIZE_MAX); 137 138 if ((d = _libelf_allocate_data(s)) == NULL) 139 return (NULL); 140 141 d->d_data.d_buf = NULL; 142 d->d_data.d_off = 0; 143 d->d_data.d_align = sh_align; 144 d->d_data.d_size = msz * count; 145 d->d_data.d_type = elftype; 146 d->d_data.d_version = e->e_version; 147 148 if (sh_type == SHT_NOBITS || sh_size == 0) { 149 STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 150 return (&d->d_data); 151 } 152 153 if ((d->d_data.d_buf = malloc(msz * count)) == NULL) { 154 (void) _libelf_release_data(d); 155 LIBELF_SET_ERROR(RESOURCE, 0); 156 return (NULL); 157 } 158 159 d->d_flags |= LIBELF_F_DATA_MALLOCED; 160 161 xlate = _libelf_get_translator(elftype, ELF_TOMEMORY, elfclass); 162 if (!(*xlate)(d->d_data.d_buf, (size_t) d->d_data.d_size, 163 e->e_rawfile + sh_offset, count, 164 e->e_byteorder != _libelf_host_byteorder())) { 165 _libelf_release_data(d); 166 LIBELF_SET_ERROR(DATA, 0); 167 return (NULL); 168 } 169 170 STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 171 172 return (&d->d_data); 173 } 174 175 Elf_Data * 176 elf_newdata(Elf_Scn *s) 177 { 178 Elf *e; 179 struct _Libelf_Data *d; 180 181 if (s == NULL || (e = s->s_elf) == NULL) { 182 LIBELF_SET_ERROR(ARGUMENT, 0); 183 return (NULL); 184 } 185 186 assert(e->e_kind == ELF_K_ELF); 187 188 /* 189 * elf_newdata() has to append a data descriptor, so 190 * bring in existing section data if not already present. 191 */ 192 if (e->e_rawfile && s->s_size > 0 && STAILQ_EMPTY(&s->s_data)) 193 if (elf_getdata(s, NULL) == NULL) 194 return (NULL); 195 196 if ((d = _libelf_allocate_data(s)) == NULL) 197 return (NULL); 198 199 STAILQ_INSERT_TAIL(&s->s_data, d, d_next); 200 201 d->d_data.d_align = 1; 202 d->d_data.d_buf = NULL; 203 d->d_data.d_off = (uint64_t) ~0; 204 d->d_data.d_size = 0; 205 d->d_data.d_type = ELF_T_BYTE; 206 d->d_data.d_version = LIBELF_PRIVATE(version); 207 208 (void) elf_flagscn(s, ELF_C_SET, ELF_F_DIRTY); 209 210 return (&d->d_data); 211 } 212 213 /* 214 * Retrieve a data descriptor for raw (untranslated) data for section 215 * `s'. 216 */ 217 218 Elf_Data * 219 elf_rawdata(Elf_Scn *s, Elf_Data *ed) 220 { 221 Elf *e; 222 int elf_class; 223 uint32_t sh_type; 224 struct _Libelf_Data *d; 225 uint64_t sh_align, sh_offset, sh_size; 226 227 if (s == NULL || (e = s->s_elf) == NULL || e->e_rawfile == NULL) { 228 LIBELF_SET_ERROR(ARGUMENT, 0); 229 return (NULL); 230 } 231 232 assert(e->e_kind == ELF_K_ELF); 233 234 d = (struct _Libelf_Data *) ed; 235 236 if (d == NULL && (d = STAILQ_FIRST(&s->s_rawdata)) != NULL) 237 return (&d->d_data); 238 239 if (d != NULL) 240 return (&STAILQ_NEXT(d, d_next)->d_data); 241 242 elf_class = e->e_class; 243 244 assert(elf_class == ELFCLASS32 || elf_class == ELFCLASS64); 245 246 if (elf_class == ELFCLASS32) { 247 sh_type = s->s_shdr.s_shdr32.sh_type; 248 sh_offset = (uint64_t) s->s_shdr.s_shdr32.sh_offset; 249 sh_size = (uint64_t) s->s_shdr.s_shdr32.sh_size; 250 sh_align = (uint64_t) s->s_shdr.s_shdr32.sh_addralign; 251 } else { 252 sh_type = s->s_shdr.s_shdr64.sh_type; 253 sh_offset = s->s_shdr.s_shdr64.sh_offset; 254 sh_size = s->s_shdr.s_shdr64.sh_size; 255 sh_align = s->s_shdr.s_shdr64.sh_addralign; 256 } 257 258 if (sh_type == SHT_NULL) { 259 LIBELF_SET_ERROR(SECTION, 0); 260 return (NULL); 261 } 262 263 if (sh_type != SHT_NOBITS && 264 sh_offset + sh_size > (uint64_t) e->e_rawsize) { 265 LIBELF_SET_ERROR(SECTION, 0); 266 return (NULL); 267 } 268 269 if ((d = _libelf_allocate_data(s)) == NULL) 270 return (NULL); 271 272 d->d_data.d_buf = (sh_type == SHT_NOBITS || sh_size == 0) ? NULL : 273 e->e_rawfile + sh_offset; 274 d->d_data.d_off = 0; 275 d->d_data.d_align = sh_align; 276 d->d_data.d_size = sh_size; 277 d->d_data.d_type = ELF_T_BYTE; 278 d->d_data.d_version = e->e_version; 279 280 STAILQ_INSERT_TAIL(&s->s_rawdata, d, d_next); 281 282 return (&d->d_data); 283 } 284