1 /* Update data structures for changes. 2 Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. 3 Written by Ulrich Drepper <drepper (at) redhat.com>, 2000. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, version 2. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software Foundation, 16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17 18 #ifdef HAVE_CONFIG_H 19 # include <config.h> 20 #endif 21 22 #include <assert.h> 23 //#include <endian.h> 24 #include <libelf.h> 25 #include <stdbool.h> 26 #include <string.h> 27 #include <sys/param.h> 28 29 #include "libelfP.h" 30 #include "elf-knowledge.h" 31 32 #ifndef LIBELFBITS 33 # define LIBELFBITS 32 34 #endif 35 36 37 38 static int 39 ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr, 40 size_t shnum, int *change_bop) 41 { 42 /* Always write the magic bytes. */ 43 if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0) 44 { 45 memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG); 46 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 47 } 48 49 /* Always set the file class. */ 50 update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS), 51 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 52 53 /* Set the data encoding if necessary. */ 54 if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE)) 55 { 56 ehdr->e_ident[EI_DATA] = 57 BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB; 58 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 59 } 60 else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM)) 61 { 62 __libelf_seterrno (ELF_E_DATA_ENCODING); 63 return 1; 64 } 65 else 66 *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN 67 && ehdr->e_ident[EI_DATA] != ELFDATA2LSB) 68 || (BYTE_ORDER == BIG_ENDIAN 69 && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)); 70 71 /* Unconditionally overwrite the ELF version. */ 72 update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT, 73 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 74 75 if (unlikely (ehdr->e_version == EV_NONE) 76 || unlikely (ehdr->e_version >= EV_NUM)) 77 { 78 __libelf_seterrno (ELF_E_UNKNOWN_VERSION); 79 return 1; 80 } 81 82 if (unlikely (shnum >= SHN_LORESERVE)) 83 { 84 update_if_changed (ehdr->e_shnum, 0, 85 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 86 } 87 else 88 update_if_changed (ehdr->e_shnum, shnum, 89 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags); 90 91 if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1))) 92 { 93 ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); 94 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY; 95 } 96 97 return 0; 98 } 99 100 101 off_t 102 internal_function_def 103 __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum) 104 { 105 ElfW2(LIBELFBITS,Ehdr) *ehdr = INTUSE(elfw2(LIBELFBITS,getehdr)) (elf); 106 int changed = 0; 107 int ehdr_flags = 0; 108 off_t size; 109 110 /* Set the default values. */ 111 if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0) 112 return -1; 113 114 /* At least the ELF header is there. */ 115 size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1); 116 117 /* Set the program header position. */ 118 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) 119 { 120 /* Only executables or shared objects have a program header. */ 121 if (ehdr->e_type != ET_EXEC && unlikely (ehdr->e_type != ET_DYN)) 122 { 123 __libelf_seterrno (ELF_E_INVALID_PHDR); 124 return -1; 125 } 126 127 if (elf->flags & ELF_F_LAYOUT) 128 { 129 /* The user is supposed to fill out e_phoff. Use it and 130 e_phnum to determine the maximum extend. */ 131 size = MAX ((size_t) size, 132 ehdr->e_phoff 133 + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum)); 134 } 135 else 136 { 137 update_if_changed (ehdr->e_phoff, 138 elf_typesize (LIBELFBITS, ELF_T_EHDR, 1), 139 ehdr_flags); 140 141 /* We need no alignment here. */ 142 size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum); 143 } 144 } 145 146 if (shnum > 0) 147 { 148 Elf_ScnList *list; 149 bool first = true; 150 151 assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0); 152 153 if (shnum >= SHN_LORESERVE) 154 { 155 /* We have to fill in the number of sections in the header 156 of the zeroth section. */ 157 elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr.ELFW(e,LIBELFBITS)->sh_size 158 = shnum; 159 elf->state.ELFW(elf,LIBELFBITS).scns.data[0].shdr_flags 160 |= ELF_F_DIRTY; 161 } 162 163 164 /* Go over all sections and find out how large they are. */ 165 list = &elf->state.ELFW(elf,LIBELFBITS).scns; 166 167 do 168 { 169 size_t cnt; 170 171 for (cnt = first == true; cnt < list->cnt; ++cnt) 172 { 173 Elf_Scn *scn = &list->data[cnt]; 174 ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); 175 off_t offset = 0; 176 ElfW2(LIBELFBITS,Word) sh_entsize; 177 ElfW2(LIBELFBITS,Word) sh_align; 178 179 assert (shdr != NULL); 180 sh_entsize = shdr->sh_entsize; 181 sh_align = shdr->sh_addralign ?: 1; 182 183 /* Set the sh_entsize value if we can reliably detect it. */ 184 switch (shdr->sh_type) 185 { 186 case SHT_SYMTAB: 187 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); 188 break; 189 case SHT_RELA: 190 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1); 191 break; 192 case SHT_GROUP: 193 /* Only relocatable files can contain section groups. */ 194 if (ehdr->e_type != ET_REL) 195 { 196 __libelf_seterrno (ELF_E_GROUP_NOT_REL); 197 return -1; 198 } 199 /* FALLTHROUGH */ 200 case SHT_SYMTAB_SHNDX: 201 sh_entsize = elf_typesize (32, ELF_T_WORD, 1); 202 break; 203 case SHT_HASH: 204 sh_entsize = SH_ENTSIZE_HASH (ehdr); 205 break; 206 case SHT_DYNAMIC: 207 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1); 208 break; 209 case SHT_REL: 210 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1); 211 break; 212 case SHT_DYNSYM: 213 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1); 214 break; 215 case SHT_SUNW_move: 216 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1); 217 break; 218 case SHT_SUNW_syminfo: 219 sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1); 220 break; 221 default: 222 break; 223 } 224 225 /* If the section header contained the wrong entry size 226 correct it and mark the header as modified. */ 227 update_if_changed (shdr->sh_entsize, sh_entsize, 228 scn->shdr_flags); 229 230 /* Iterate over all data blocks. */ 231 if (list->data[cnt].data_list_rear != NULL) 232 { 233 Elf_Data_List *dl = &scn->data_list; 234 235 while (dl != NULL) 236 { 237 if (unlikely (dl->data.d.d_version == EV_NONE) 238 || unlikely (dl->data.d.d_version >= EV_NUM)) 239 { 240 __libelf_seterrno (ELF_E_UNKNOWN_VERSION); 241 return -1; 242 } 243 244 if (unlikely (! powerof2 (dl->data.d.d_align))) 245 { 246 __libelf_seterrno (ELF_E_INVALID_ALIGN); 247 return -1; 248 } 249 250 sh_align = MAX (sh_align, dl->data.d.d_align); 251 252 if (elf->flags & ELF_F_LAYOUT) 253 { 254 /* The user specified the offset and the size. 255 All we have to do is check whether this block 256 fits in the size specified for the section. */ 257 if (unlikely ((GElf_Word) (dl->data.d.d_off 258 + dl->data.d.d_size) 259 > shdr->sh_size)) 260 { 261 __libelf_seterrno (ELF_E_SECTION_TOO_SMALL); 262 return -1; 263 } 264 } 265 else 266 { 267 /* Determine the padding. */ 268 offset = ((offset + dl->data.d.d_align - 1) 269 & ~(dl->data.d.d_align - 1)); 270 271 update_if_changed (dl->data.d.d_off, offset, 272 changed); 273 274 offset += dl->data.d.d_size; 275 } 276 277 /* Next data block. */ 278 dl = dl->next; 279 } 280 } 281 282 if (elf->flags & ELF_F_LAYOUT) 283 { 284 size = MAX ((GElf_Word) size, 285 shdr->sh_offset 286 + (shdr->sh_type != SHT_NOBITS 287 ? shdr->sh_size : 0)); 288 289 /* The alignment must be a power of two. This is a 290 requirement from the ELF specification. Additionally 291 we test for the alignment of the section being large 292 enough for the largest alignment required by a data 293 block. */ 294 if (unlikely (! powerof2 (shdr->sh_addralign)) 295 || unlikely (shdr->sh_addralign < sh_align)) 296 { 297 __libelf_seterrno (ELF_E_INVALID_ALIGN); 298 return -1; 299 } 300 } 301 else 302 { 303 /* How much alignment do we need for this section. */ 304 update_if_changed (shdr->sh_addralign, sh_align, 305 scn->shdr_flags); 306 307 size = (size + sh_align - 1) & ~(sh_align - 1); 308 update_if_changed (shdr->sh_offset, (GElf_Word) size, 309 changed); 310 311 /* See whether the section size is correct. */ 312 update_if_changed (shdr->sh_size, (GElf_Word) offset, 313 changed); 314 315 if (shdr->sh_type != SHT_NOBITS) 316 size += offset; 317 318 scn->flags |= changed; 319 } 320 321 /* Check that the section size is actually a multiple of 322 the entry size. */ 323 if (shdr->sh_entsize != 0 324 && unlikely (shdr->sh_size % shdr->sh_entsize != 0) 325 && (elf->flags & ELF_F_PERMISSIVE) == 0) 326 { 327 __libelf_seterrno (ELF_E_INVALID_SHENTSIZE); 328 return -1; 329 } 330 } 331 332 assert (list->next == NULL || list->cnt == list->max); 333 334 first = false; 335 } 336 while ((list = list->next) != NULL); 337 338 /* Store section information. */ 339 if (elf->flags & ELF_F_LAYOUT) 340 { 341 /* The user is supposed to fill out e_phoff. Use it and 342 e_phnum to determine the maximum extend. */ 343 size = MAX ((GElf_Word) size, 344 (ehdr->e_shoff 345 + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum)))); 346 } 347 else 348 { 349 /* Align for section header table. 350 351 Yes, we use `sizeof' and not `__alignof__' since we do not 352 want to be surprised by architectures with less strict 353 alignment rules. */ 354 #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off)) 355 size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1); 356 357 update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags); 358 update_if_changed (ehdr->e_shentsize, 359 elf_typesize (LIBELFBITS, ELF_T_SHDR, 1), 360 ehdr_flags); 361 362 /* Account for the section header size. */ 363 size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum); 364 } 365 } 366 367 elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags; 368 369 return size; 370 } 371