Brian Silverman | 8649792 | 2018-02-10 19:28:39 -0500 | [diff] [blame^] | 1 | /* Pedantic checking of ELF files compliance with gABI/psABI spec. |
| 2 | Copyright (C) 2001-2015, 2017 Red Hat, Inc. |
| 3 | This file is part of elfutils. |
| 4 | Written by Ulrich Drepper <drepper@redhat.com>, 2001. |
| 5 | |
| 6 | This file is free software; you can redistribute it and/or modify |
| 7 | it under the terms of the GNU General Public License as published by |
| 8 | the Free Software Foundation; either version 3 of the License, or |
| 9 | (at your option) any later version. |
| 10 | |
| 11 | elfutils is distributed in the hope that it will be useful, but |
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | GNU General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU General Public License |
| 17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | #ifdef HAVE_CONFIG_H |
| 20 | # include <config.h> |
| 21 | #endif |
| 22 | |
| 23 | #include <argp.h> |
| 24 | #include <assert.h> |
| 25 | #include <byteswap.h> |
| 26 | #include <endian.h> |
| 27 | #include <error.h> |
| 28 | #include <fcntl.h> |
| 29 | #include <gelf.h> |
| 30 | #include <inttypes.h> |
| 31 | #include <libintl.h> |
| 32 | #include <locale.h> |
| 33 | #include <stdbool.h> |
| 34 | #include <stdlib.h> |
| 35 | #include <string.h> |
| 36 | #include <unistd.h> |
| 37 | #include <sys/stat.h> |
| 38 | |
| 39 | #include <elf-knowledge.h> |
| 40 | #include <libeu.h> |
| 41 | #include <system.h> |
| 42 | #include <printversion.h> |
| 43 | #include "../libelf/libelfP.h" |
| 44 | #include "../libelf/common.h" |
| 45 | #include "../libebl/libeblP.h" |
| 46 | #include "../libdw/libdwP.h" |
| 47 | #include "../libdwfl/libdwflP.h" |
| 48 | #include "../libdw/memory-access.h" |
| 49 | |
| 50 | |
| 51 | /* Name and version of program. */ |
| 52 | ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; |
| 53 | |
| 54 | /* Bug report address. */ |
| 55 | ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; |
| 56 | |
| 57 | #define ARGP_strict 300 |
| 58 | #define ARGP_gnuld 301 |
| 59 | |
| 60 | /* Definitions of arguments for argp functions. */ |
| 61 | static const struct argp_option options[] = |
| 62 | { |
| 63 | { "strict", ARGP_strict, NULL, 0, |
| 64 | N_("Be extremely strict, flag level 2 features."), 0 }, |
| 65 | { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 }, |
| 66 | { "debuginfo", 'd', NULL, 0, N_("Binary is a separate debuginfo file"), 0 }, |
| 67 | { "gnu-ld", ARGP_gnuld, NULL, 0, |
| 68 | N_("Binary has been created with GNU ld and is therefore known to be \ |
| 69 | broken in certain ways"), 0 }, |
| 70 | { NULL, 0, NULL, 0, NULL, 0 } |
| 71 | }; |
| 72 | |
| 73 | /* Short description of program. */ |
| 74 | static const char doc[] = N_("\ |
| 75 | Pedantic checking of ELF files compliance with gABI/psABI spec."); |
| 76 | |
| 77 | /* Strings for arguments in help texts. */ |
| 78 | static const char args_doc[] = N_("FILE..."); |
| 79 | |
| 80 | /* Prototype for option handler. */ |
| 81 | static error_t parse_opt (int key, char *arg, struct argp_state *state); |
| 82 | |
| 83 | /* Data structure to communicate with argp functions. */ |
| 84 | static struct argp argp = |
| 85 | { |
| 86 | options, parse_opt, args_doc, doc, NULL, NULL, NULL |
| 87 | }; |
| 88 | |
| 89 | |
| 90 | /* Declarations of local functions. */ |
| 91 | static void process_file (int fd, Elf *elf, const char *prefix, |
| 92 | const char *suffix, const char *fname, size_t size, |
| 93 | bool only_one); |
| 94 | static void process_elf_file (Elf *elf, const char *prefix, const char *suffix, |
| 95 | const char *fname, size_t size, bool only_one); |
| 96 | static void check_note_section (Ebl *ebl, GElf_Ehdr *ehdr, |
| 97 | GElf_Shdr *shdr, int idx); |
| 98 | |
| 99 | |
| 100 | /* Report an error. */ |
| 101 | #define ERROR(str, args...) \ |
| 102 | do { \ |
| 103 | printf (str, ##args); \ |
| 104 | ++error_count; \ |
| 105 | } while (0) |
| 106 | static unsigned int error_count; |
| 107 | |
| 108 | /* True if we should perform very strict testing. */ |
| 109 | static bool be_strict; |
| 110 | |
| 111 | /* True if no message is to be printed if the run is succesful. */ |
| 112 | static bool be_quiet; |
| 113 | |
| 114 | /* True if binary is from strip -f, not a normal ELF file. */ |
| 115 | static bool is_debuginfo; |
| 116 | |
| 117 | /* True if binary is assumed to be generated with GNU ld. */ |
| 118 | static bool gnuld; |
| 119 | |
| 120 | /* Index of section header string table. */ |
| 121 | static uint32_t shstrndx; |
| 122 | |
| 123 | /* Array to count references in section groups. */ |
| 124 | static int *scnref; |
| 125 | |
| 126 | /* Numbers of sections and program headers. */ |
| 127 | static unsigned int shnum; |
| 128 | static unsigned int phnum; |
| 129 | |
| 130 | |
| 131 | int |
| 132 | main (int argc, char *argv[]) |
| 133 | { |
| 134 | /* Set locale. */ |
| 135 | setlocale (LC_ALL, ""); |
| 136 | |
| 137 | /* Initialize the message catalog. */ |
| 138 | textdomain (PACKAGE_TARNAME); |
| 139 | |
| 140 | /* Parse and process arguments. */ |
| 141 | int remaining; |
| 142 | argp_parse (&argp, argc, argv, 0, &remaining, NULL); |
| 143 | |
| 144 | /* Before we start tell the ELF library which version we are using. */ |
| 145 | elf_version (EV_CURRENT); |
| 146 | |
| 147 | /* Now process all the files given at the command line. */ |
| 148 | bool only_one = remaining + 1 == argc; |
| 149 | do |
| 150 | { |
| 151 | /* Open the file. */ |
| 152 | int fd = open (argv[remaining], O_RDONLY); |
| 153 | if (fd == -1) |
| 154 | { |
| 155 | error (0, errno, gettext ("cannot open input file")); |
| 156 | continue; |
| 157 | } |
| 158 | |
| 159 | /* Create an `Elf' descriptor. */ |
| 160 | Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); |
| 161 | if (elf == NULL) |
| 162 | ERROR (gettext ("cannot generate Elf descriptor: %s\n"), |
| 163 | elf_errmsg (-1)); |
| 164 | else |
| 165 | { |
| 166 | unsigned int prev_error_count = error_count; |
| 167 | struct stat st; |
| 168 | |
| 169 | if (fstat (fd, &st) != 0) |
| 170 | { |
| 171 | printf ("cannot stat '%s': %m\n", argv[remaining]); |
| 172 | close (fd); |
| 173 | continue; |
| 174 | } |
| 175 | |
| 176 | process_file (fd, elf, NULL, NULL, argv[remaining], st.st_size, |
| 177 | only_one); |
| 178 | |
| 179 | /* Now we can close the descriptor. */ |
| 180 | if (elf_end (elf) != 0) |
| 181 | ERROR (gettext ("error while closing Elf descriptor: %s\n"), |
| 182 | elf_errmsg (-1)); |
| 183 | |
| 184 | if (prev_error_count == error_count && !be_quiet) |
| 185 | puts (gettext ("No errors")); |
| 186 | } |
| 187 | |
| 188 | close (fd); |
| 189 | } |
| 190 | while (++remaining < argc); |
| 191 | |
| 192 | return error_count != 0; |
| 193 | } |
| 194 | |
| 195 | |
| 196 | /* Handle program arguments. */ |
| 197 | static error_t |
| 198 | parse_opt (int key, char *arg __attribute__ ((unused)), |
| 199 | struct argp_state *state __attribute__ ((unused))) |
| 200 | { |
| 201 | switch (key) |
| 202 | { |
| 203 | case ARGP_strict: |
| 204 | be_strict = true; |
| 205 | break; |
| 206 | |
| 207 | case 'q': |
| 208 | be_quiet = true; |
| 209 | break; |
| 210 | |
| 211 | case 'd': |
| 212 | is_debuginfo = true; |
| 213 | break; |
| 214 | |
| 215 | case ARGP_gnuld: |
| 216 | gnuld = true; |
| 217 | break; |
| 218 | |
| 219 | case ARGP_KEY_NO_ARGS: |
| 220 | fputs (gettext ("Missing file name.\n"), stderr); |
| 221 | argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name); |
| 222 | exit (EXIT_FAILURE); |
| 223 | |
| 224 | default: |
| 225 | return ARGP_ERR_UNKNOWN; |
| 226 | } |
| 227 | return 0; |
| 228 | } |
| 229 | |
| 230 | |
| 231 | /* Process one file. */ |
| 232 | static void |
| 233 | process_file (int fd, Elf *elf, const char *prefix, const char *suffix, |
| 234 | const char *fname, size_t size, bool only_one) |
| 235 | { |
| 236 | /* We can handle two types of files: ELF files and archives. */ |
| 237 | Elf_Kind kind = elf_kind (elf); |
| 238 | |
| 239 | switch (kind) |
| 240 | { |
| 241 | case ELF_K_ELF: |
| 242 | /* Yes! It's an ELF file. */ |
| 243 | process_elf_file (elf, prefix, suffix, fname, size, only_one); |
| 244 | break; |
| 245 | |
| 246 | case ELF_K_AR: |
| 247 | { |
| 248 | Elf *subelf; |
| 249 | Elf_Cmd cmd = ELF_C_READ_MMAP; |
| 250 | size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); |
| 251 | size_t fname_len = strlen (fname) + 1; |
| 252 | char new_prefix[prefix_len + 1 + fname_len]; |
| 253 | char new_suffix[(suffix == NULL ? 0 : strlen (suffix)) + 2]; |
| 254 | char *cp = new_prefix; |
| 255 | |
| 256 | /* Create the full name of the file. */ |
| 257 | if (prefix != NULL) |
| 258 | { |
| 259 | cp = mempcpy (cp, prefix, prefix_len); |
| 260 | *cp++ = '('; |
| 261 | strcpy (stpcpy (new_suffix, suffix), ")"); |
| 262 | } |
| 263 | else |
| 264 | new_suffix[0] = '\0'; |
| 265 | memcpy (cp, fname, fname_len); |
| 266 | |
| 267 | /* It's an archive. We process each file in it. */ |
| 268 | while ((subelf = elf_begin (fd, cmd, elf)) != NULL) |
| 269 | { |
| 270 | kind = elf_kind (subelf); |
| 271 | |
| 272 | /* Call this function recursively. */ |
| 273 | if (kind == ELF_K_ELF || kind == ELF_K_AR) |
| 274 | { |
| 275 | Elf_Arhdr *arhdr = elf_getarhdr (subelf); |
| 276 | assert (arhdr != NULL); |
| 277 | |
| 278 | process_file (fd, subelf, new_prefix, new_suffix, |
| 279 | arhdr->ar_name, arhdr->ar_size, false); |
| 280 | } |
| 281 | |
| 282 | /* Get next archive element. */ |
| 283 | cmd = elf_next (subelf); |
| 284 | if (elf_end (subelf) != 0) |
| 285 | ERROR (gettext (" error while freeing sub-ELF descriptor: %s\n"), |
| 286 | elf_errmsg (-1)); |
| 287 | } |
| 288 | } |
| 289 | break; |
| 290 | |
| 291 | default: |
| 292 | /* We cannot do anything. */ |
| 293 | ERROR (gettext ("\ |
| 294 | Not an ELF file - it has the wrong magic bytes at the start\n")); |
| 295 | break; |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | |
| 300 | static const char * |
| 301 | section_name (Ebl *ebl, int idx) |
| 302 | { |
| 303 | GElf_Shdr shdr_mem; |
| 304 | GElf_Shdr *shdr; |
| 305 | const char *ret; |
| 306 | |
| 307 | if ((unsigned int) idx > shnum) |
| 308 | return "<invalid>"; |
| 309 | |
| 310 | shdr = gelf_getshdr (elf_getscn (ebl->elf, idx), &shdr_mem); |
| 311 | if (shdr == NULL) |
| 312 | return "<invalid>"; |
| 313 | |
| 314 | ret = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); |
| 315 | if (ret == NULL) |
| 316 | return "<invalid>"; |
| 317 | return ret; |
| 318 | } |
| 319 | |
| 320 | |
| 321 | static const int valid_e_machine[] = |
| 322 | { |
| 323 | EM_M32, EM_SPARC, EM_386, EM_68K, EM_88K, EM_860, EM_MIPS, EM_S370, |
| 324 | EM_MIPS_RS3_LE, EM_PARISC, EM_VPP500, EM_SPARC32PLUS, EM_960, EM_PPC, |
| 325 | EM_PPC64, EM_S390, EM_V800, EM_FR20, EM_RH32, EM_RCE, EM_ARM, |
| 326 | EM_FAKE_ALPHA, EM_SH, EM_SPARCV9, EM_TRICORE, EM_ARC, EM_H8_300, |
| 327 | EM_H8_300H, EM_H8S, EM_H8_500, EM_IA_64, EM_MIPS_X, EM_COLDFIRE, |
| 328 | EM_68HC12, EM_MMA, EM_PCP, EM_NCPU, EM_NDR1, EM_STARCORE, EM_ME16, |
| 329 | EM_ST100, EM_TINYJ, EM_X86_64, EM_PDSP, EM_FX66, EM_ST9PLUS, EM_ST7, |
| 330 | EM_68HC16, EM_68HC11, EM_68HC08, EM_68HC05, EM_SVX, EM_ST19, EM_VAX, |
| 331 | EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM, |
| 332 | EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300, |
| 333 | EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA, EM_ALPHA, |
| 334 | EM_TILEGX, EM_TILEPRO, EM_AARCH64, EM_BPF |
| 335 | }; |
| 336 | #define nvalid_e_machine \ |
| 337 | (sizeof (valid_e_machine) / sizeof (valid_e_machine[0])) |
| 338 | |
| 339 | |
| 340 | static void |
| 341 | check_elf_header (Ebl *ebl, GElf_Ehdr *ehdr, size_t size) |
| 342 | { |
| 343 | char buf[512]; |
| 344 | size_t cnt; |
| 345 | |
| 346 | /* Check e_ident field. */ |
| 347 | if (ehdr->e_ident[EI_MAG0] != ELFMAG0) |
| 348 | ERROR ("e_ident[%d] != '%c'\n", EI_MAG0, ELFMAG0); |
| 349 | if (ehdr->e_ident[EI_MAG1] != ELFMAG1) |
| 350 | ERROR ("e_ident[%d] != '%c'\n", EI_MAG1, ELFMAG1); |
| 351 | if (ehdr->e_ident[EI_MAG2] != ELFMAG2) |
| 352 | ERROR ("e_ident[%d] != '%c'\n", EI_MAG2, ELFMAG2); |
| 353 | if (ehdr->e_ident[EI_MAG3] != ELFMAG3) |
| 354 | ERROR ("e_ident[%d] != '%c'\n", EI_MAG3, ELFMAG3); |
| 355 | |
| 356 | if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 |
| 357 | && ehdr->e_ident[EI_CLASS] != ELFCLASS64) |
| 358 | ERROR (gettext ("e_ident[%d] == %d is no known class\n"), |
| 359 | EI_CLASS, ehdr->e_ident[EI_CLASS]); |
| 360 | |
| 361 | if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB |
| 362 | && ehdr->e_ident[EI_DATA] != ELFDATA2MSB) |
| 363 | ERROR (gettext ("e_ident[%d] == %d is no known data encoding\n"), |
| 364 | EI_DATA, ehdr->e_ident[EI_DATA]); |
| 365 | |
| 366 | if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) |
| 367 | ERROR (gettext ("unknown ELF header version number e_ident[%d] == %d\n"), |
| 368 | EI_VERSION, ehdr->e_ident[EI_VERSION]); |
| 369 | |
| 370 | /* We currently don't handle any OS ABIs other than Linux and the |
| 371 | kFreeBSD variant of Debian. */ |
| 372 | if (ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE |
| 373 | && ehdr->e_ident[EI_OSABI] != ELFOSABI_LINUX |
| 374 | && ehdr->e_ident[EI_OSABI] != ELFOSABI_FREEBSD) |
| 375 | ERROR (gettext ("unsupported OS ABI e_ident[%d] == '%s'\n"), |
| 376 | EI_OSABI, |
| 377 | ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf))); |
| 378 | |
| 379 | /* No ABI versions other than zero supported either. */ |
| 380 | if (ehdr->e_ident[EI_ABIVERSION] != 0) |
| 381 | ERROR (gettext ("unsupport ABI version e_ident[%d] == %d\n"), |
| 382 | EI_ABIVERSION, ehdr->e_ident[EI_ABIVERSION]); |
| 383 | |
| 384 | for (cnt = EI_PAD; cnt < EI_NIDENT; ++cnt) |
| 385 | if (ehdr->e_ident[cnt] != 0) |
| 386 | ERROR (gettext ("e_ident[%zu] is not zero\n"), cnt); |
| 387 | |
| 388 | /* Check the e_type field. */ |
| 389 | if (ehdr->e_type != ET_REL && ehdr->e_type != ET_EXEC |
| 390 | && ehdr->e_type != ET_DYN && ehdr->e_type != ET_CORE) |
| 391 | ERROR (gettext ("unknown object file type %d\n"), ehdr->e_type); |
| 392 | |
| 393 | /* Check the e_machine field. */ |
| 394 | for (cnt = 0; cnt < nvalid_e_machine; ++cnt) |
| 395 | if (valid_e_machine[cnt] == ehdr->e_machine) |
| 396 | break; |
| 397 | if (cnt == nvalid_e_machine) |
| 398 | ERROR (gettext ("unknown machine type %d\n"), ehdr->e_machine); |
| 399 | |
| 400 | /* Check the e_version field. */ |
| 401 | if (ehdr->e_version != EV_CURRENT) |
| 402 | ERROR (gettext ("unknown object file version\n")); |
| 403 | |
| 404 | /* Check the e_phoff and e_phnum fields. */ |
| 405 | if (ehdr->e_phoff == 0) |
| 406 | { |
| 407 | if (ehdr->e_phnum != 0) |
| 408 | ERROR (gettext ("invalid program header offset\n")); |
| 409 | else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) |
| 410 | ERROR (gettext ("\ |
| 411 | executables and DSOs cannot have zero program header offset\n")); |
| 412 | } |
| 413 | else if (ehdr->e_phnum == 0) |
| 414 | ERROR (gettext ("invalid number of program header entries\n")); |
| 415 | |
| 416 | /* Check the e_shoff field. */ |
| 417 | shnum = ehdr->e_shnum; |
| 418 | shstrndx = ehdr->e_shstrndx; |
| 419 | if (ehdr->e_shoff == 0) |
| 420 | { |
| 421 | if (ehdr->e_shnum != 0) |
| 422 | ERROR (gettext ("invalid section header table offset\n")); |
| 423 | else if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN |
| 424 | && ehdr->e_type != ET_CORE) |
| 425 | ERROR (gettext ("section header table must be present\n")); |
| 426 | } |
| 427 | else |
| 428 | { |
| 429 | if (ehdr->e_shnum == 0) |
| 430 | { |
| 431 | /* Get the header of the zeroth section. The sh_size field |
| 432 | might contain the section number. */ |
| 433 | GElf_Shdr shdr_mem; |
| 434 | GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); |
| 435 | if (shdr != NULL) |
| 436 | { |
| 437 | /* The error will be reported later. */ |
| 438 | if (shdr->sh_size == 0) |
| 439 | ERROR (gettext ("\ |
| 440 | invalid number of section header table entries\n")); |
| 441 | else |
| 442 | shnum = shdr->sh_size; |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | if (ehdr->e_shstrndx == SHN_XINDEX) |
| 447 | { |
| 448 | /* Get the header of the zeroth section. The sh_size field |
| 449 | might contain the section number. */ |
| 450 | GElf_Shdr shdr_mem; |
| 451 | GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); |
| 452 | if (shdr != NULL && shdr->sh_link < shnum) |
| 453 | shstrndx = shdr->sh_link; |
| 454 | } |
| 455 | else if (shstrndx >= shnum) |
| 456 | ERROR (gettext ("invalid section header index\n")); |
| 457 | } |
| 458 | |
| 459 | /* Check the shdrs actually exist. And uncompress them before |
| 460 | further checking. Indexes between sections reference the |
| 461 | uncompressed data. */ |
| 462 | unsigned int scnt; |
| 463 | Elf_Scn *scn = NULL; |
| 464 | for (scnt = 1; scnt < shnum; ++scnt) |
| 465 | { |
| 466 | scn = elf_nextscn (ebl->elf, scn); |
| 467 | if (scn == NULL) |
| 468 | break; |
| 469 | /* If the section wasn't compressed this does nothing, but |
| 470 | returns an error. We don't care. */ |
| 471 | elf_compress (scn, 0, 0); |
| 472 | } |
| 473 | if (scnt < shnum) |
| 474 | ERROR (gettext ("Can only check %u headers, shnum was %u\n"), scnt, shnum); |
| 475 | shnum = scnt; |
| 476 | |
| 477 | phnum = ehdr->e_phnum; |
| 478 | if (ehdr->e_phnum == PN_XNUM) |
| 479 | { |
| 480 | /* Get the header of the zeroth section. The sh_info field |
| 481 | might contain the phnum count. */ |
| 482 | GElf_Shdr shdr_mem; |
| 483 | GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); |
| 484 | if (shdr != NULL) |
| 485 | { |
| 486 | /* The error will be reported later. */ |
| 487 | if (shdr->sh_info < PN_XNUM) |
| 488 | ERROR (gettext ("\ |
| 489 | invalid number of program header table entries\n")); |
| 490 | else |
| 491 | phnum = shdr->sh_info; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | /* Check the phdrs actually exist. */ |
| 496 | unsigned int pcnt; |
| 497 | for (pcnt = 0; pcnt < phnum; ++pcnt) |
| 498 | { |
| 499 | GElf_Phdr phdr_mem; |
| 500 | GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); |
| 501 | if (phdr == NULL) |
| 502 | break; |
| 503 | } |
| 504 | if (pcnt < phnum) |
| 505 | ERROR (gettext ("Can only check %u headers, phnum was %u\n"), pcnt, phnum); |
| 506 | phnum = pcnt; |
| 507 | |
| 508 | /* Check the e_flags field. */ |
| 509 | if (!ebl_machine_flag_check (ebl, ehdr->e_flags)) |
| 510 | ERROR (gettext ("invalid machine flags: %s\n"), |
| 511 | ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf))); |
| 512 | |
| 513 | /* Check e_ehsize, e_phentsize, and e_shentsize fields. */ |
| 514 | if (gelf_getclass (ebl->elf) == ELFCLASS32) |
| 515 | { |
| 516 | if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf32_Ehdr)) |
| 517 | ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize); |
| 518 | |
| 519 | if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf32_Phdr)) |
| 520 | ERROR (gettext ("invalid program header size: %hd\n"), |
| 521 | ehdr->e_phentsize); |
| 522 | else if (ehdr->e_phoff + phnum * ehdr->e_phentsize > size) |
| 523 | ERROR (gettext ("invalid program header position or size\n")); |
| 524 | |
| 525 | if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf32_Shdr)) |
| 526 | ERROR (gettext ("invalid section header size: %hd\n"), |
| 527 | ehdr->e_shentsize); |
| 528 | else if (ehdr->e_shoff + shnum * ehdr->e_shentsize > size) |
| 529 | ERROR (gettext ("invalid section header position or size\n")); |
| 530 | } |
| 531 | else if (gelf_getclass (ebl->elf) == ELFCLASS64) |
| 532 | { |
| 533 | if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf64_Ehdr)) |
| 534 | ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize); |
| 535 | |
| 536 | if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf64_Phdr)) |
| 537 | ERROR (gettext ("invalid program header size: %hd\n"), |
| 538 | ehdr->e_phentsize); |
| 539 | else if (ehdr->e_phoff + phnum * ehdr->e_phentsize > size) |
| 540 | ERROR (gettext ("invalid program header position or size\n")); |
| 541 | |
| 542 | if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr)) |
| 543 | ERROR (gettext ("invalid section header size: %hd\n"), |
| 544 | ehdr->e_shentsize); |
| 545 | else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) |
| 546 | ERROR (gettext ("invalid section header position or size\n")); |
| 547 | } |
| 548 | } |
| 549 | |
| 550 | |
| 551 | /* Check that there is a section group section with index < IDX which |
| 552 | contains section IDX and that there is exactly one. */ |
| 553 | static void |
| 554 | check_scn_group (Ebl *ebl, int idx) |
| 555 | { |
| 556 | if (scnref[idx] == 0) |
| 557 | { |
| 558 | /* No reference so far. Search following sections, maybe the |
| 559 | order is wrong. */ |
| 560 | size_t cnt; |
| 561 | |
| 562 | for (cnt = idx + 1; cnt < shnum; ++cnt) |
| 563 | { |
| 564 | Elf_Scn *scn = elf_getscn (ebl->elf, cnt); |
| 565 | GElf_Shdr shdr_mem; |
| 566 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); |
| 567 | if (shdr == NULL) |
| 568 | /* We cannot get the section header so we cannot check it. |
| 569 | The error to get the section header will be shown |
| 570 | somewhere else. */ |
| 571 | continue; |
| 572 | |
| 573 | if (shdr->sh_type != SHT_GROUP) |
| 574 | continue; |
| 575 | |
| 576 | Elf_Data *data = elf_getdata (scn, NULL); |
| 577 | if (data == NULL || data->d_buf == NULL |
| 578 | || data->d_size < sizeof (Elf32_Word)) |
| 579 | /* Cannot check the section. */ |
| 580 | continue; |
| 581 | |
| 582 | Elf32_Word *grpdata = (Elf32_Word *) data->d_buf; |
| 583 | for (size_t inner = 1; inner < data->d_size / sizeof (Elf32_Word); |
| 584 | ++inner) |
| 585 | if (grpdata[inner] == (Elf32_Word) idx) |
| 586 | goto out; |
| 587 | } |
| 588 | |
| 589 | out: |
| 590 | if (cnt == shnum) |
| 591 | ERROR (gettext ("\ |
| 592 | section [%2d] '%s': section with SHF_GROUP flag set not part of a section group\n"), |
| 593 | idx, section_name (ebl, idx)); |
| 594 | else |
| 595 | ERROR (gettext ("\ |
| 596 | section [%2d] '%s': section group [%2zu] '%s' does not precede group member\n"), |
| 597 | idx, section_name (ebl, idx), |
| 598 | cnt, section_name (ebl, cnt)); |
| 599 | } |
| 600 | } |
| 601 | |
| 602 | |
| 603 | static void |
| 604 | check_symtab (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 605 | { |
| 606 | bool no_xndx_warned = false; |
| 607 | int no_pt_tls = 0; |
| 608 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 609 | if (data == NULL) |
| 610 | { |
| 611 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 612 | idx, section_name (ebl, idx)); |
| 613 | return; |
| 614 | } |
| 615 | |
| 616 | GElf_Shdr strshdr_mem; |
| 617 | GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), |
| 618 | &strshdr_mem); |
| 619 | if (strshdr == NULL) |
| 620 | return; |
| 621 | |
| 622 | if (strshdr->sh_type != SHT_STRTAB) |
| 623 | { |
| 624 | ERROR (gettext ("section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"), |
| 625 | shdr->sh_link, section_name (ebl, shdr->sh_link), |
| 626 | idx, section_name (ebl, idx)); |
| 627 | strshdr = NULL; |
| 628 | } |
| 629 | |
| 630 | /* Search for an extended section index table section. */ |
| 631 | Elf_Data *xndxdata = NULL; |
| 632 | Elf32_Word xndxscnidx = 0; |
| 633 | bool found_xndx = false; |
| 634 | for (size_t cnt = 1; cnt < shnum; ++cnt) |
| 635 | if (cnt != (size_t) idx) |
| 636 | { |
| 637 | Elf_Scn *xndxscn = elf_getscn (ebl->elf, cnt); |
| 638 | GElf_Shdr xndxshdr_mem; |
| 639 | GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); |
| 640 | if (xndxshdr == NULL) |
| 641 | continue; |
| 642 | |
| 643 | if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX |
| 644 | && xndxshdr->sh_link == (GElf_Word) idx) |
| 645 | { |
| 646 | if (found_xndx) |
| 647 | ERROR (gettext ("\ |
| 648 | section [%2d] '%s': symbol table cannot have more than one extended index section\n"), |
| 649 | idx, section_name (ebl, idx)); |
| 650 | |
| 651 | xndxdata = elf_getdata (xndxscn, NULL); |
| 652 | xndxscnidx = elf_ndxscn (xndxscn); |
| 653 | found_xndx = true; |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT); |
| 658 | if (shdr->sh_entsize != sh_entsize) |
| 659 | ERROR (gettext ("\ |
| 660 | section [%2u] '%s': entry size is does not match ElfXX_Sym\n"), |
| 661 | idx, section_name (ebl, idx)); |
| 662 | |
| 663 | /* Test the zeroth entry. */ |
| 664 | GElf_Sym sym_mem; |
| 665 | Elf32_Word xndx; |
| 666 | GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, 0, &sym_mem, &xndx); |
| 667 | if (sym == NULL) |
| 668 | ERROR (gettext ("section [%2d] '%s': cannot get symbol %d: %s\n"), |
| 669 | idx, section_name (ebl, idx), 0, elf_errmsg (-1)); |
| 670 | else |
| 671 | { |
| 672 | if (sym->st_name != 0) |
| 673 | ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), |
| 674 | idx, section_name (ebl, idx), "st_name"); |
| 675 | if (sym->st_value != 0) |
| 676 | ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), |
| 677 | idx, section_name (ebl, idx), "st_value"); |
| 678 | if (sym->st_size != 0) |
| 679 | ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), |
| 680 | idx, section_name (ebl, idx), "st_size"); |
| 681 | if (sym->st_info != 0) |
| 682 | ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), |
| 683 | idx, section_name (ebl, idx), "st_info"); |
| 684 | if (sym->st_other != 0) |
| 685 | ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), |
| 686 | idx, section_name (ebl, idx), "st_other"); |
| 687 | if (sym->st_shndx != 0) |
| 688 | ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"), |
| 689 | idx, section_name (ebl, idx), "st_shndx"); |
| 690 | if (xndxdata != NULL && xndx != 0) |
| 691 | ERROR (gettext ("\ |
| 692 | section [%2d] '%s': XINDEX for zeroth entry not zero\n"), |
| 693 | xndxscnidx, section_name (ebl, xndxscnidx)); |
| 694 | } |
| 695 | |
| 696 | for (size_t cnt = 1; cnt < shdr->sh_size / sh_entsize; ++cnt) |
| 697 | { |
| 698 | sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, &xndx); |
| 699 | if (sym == NULL) |
| 700 | { |
| 701 | ERROR (gettext ("section [%2d] '%s': cannot get symbol %zu: %s\n"), |
| 702 | idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); |
| 703 | continue; |
| 704 | } |
| 705 | |
| 706 | const char *name = NULL; |
| 707 | if (strshdr == NULL) |
| 708 | name = ""; |
| 709 | else if (sym->st_name >= strshdr->sh_size) |
| 710 | ERROR (gettext ("\ |
| 711 | section [%2d] '%s': symbol %zu: invalid name value\n"), |
| 712 | idx, section_name (ebl, idx), cnt); |
| 713 | else |
| 714 | { |
| 715 | name = elf_strptr (ebl->elf, shdr->sh_link, sym->st_name); |
| 716 | if (name == NULL) |
| 717 | name = ""; |
| 718 | } |
| 719 | |
| 720 | if (sym->st_shndx == SHN_XINDEX) |
| 721 | { |
| 722 | if (xndxdata == NULL) |
| 723 | { |
| 724 | if (!no_xndx_warned) |
| 725 | ERROR (gettext ("\ |
| 726 | section [%2d] '%s': symbol %zu: too large section index but no extended section index section\n"), |
| 727 | idx, section_name (ebl, idx), cnt); |
| 728 | no_xndx_warned = true; |
| 729 | } |
| 730 | else if (xndx < SHN_LORESERVE) |
| 731 | ERROR (gettext ("\ |
| 732 | section [%2d] '%s': symbol %zu: XINDEX used for index which would fit in st_shndx (%" PRIu32 ")\n"), |
| 733 | xndxscnidx, section_name (ebl, xndxscnidx), cnt, |
| 734 | xndx); |
| 735 | } |
| 736 | else if ((sym->st_shndx >= SHN_LORESERVE |
| 737 | // && sym->st_shndx <= SHN_HIRESERVE always true |
| 738 | && sym->st_shndx != SHN_ABS |
| 739 | && sym->st_shndx != SHN_COMMON) |
| 740 | || (sym->st_shndx >= shnum |
| 741 | && (sym->st_shndx < SHN_LORESERVE |
| 742 | /* || sym->st_shndx > SHN_HIRESERVE always false */))) |
| 743 | ERROR (gettext ("\ |
| 744 | section [%2d] '%s': symbol %zu: invalid section index\n"), |
| 745 | idx, section_name (ebl, idx), cnt); |
| 746 | else |
| 747 | xndx = sym->st_shndx; |
| 748 | |
| 749 | if (GELF_ST_TYPE (sym->st_info) >= STT_NUM |
| 750 | && !ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), NULL, 0)) |
| 751 | ERROR (gettext ("section [%2d] '%s': symbol %zu: unknown type\n"), |
| 752 | idx, section_name (ebl, idx), cnt); |
| 753 | |
| 754 | if (GELF_ST_BIND (sym->st_info) >= STB_NUM |
| 755 | && !ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info), NULL, |
| 756 | 0)) |
| 757 | ERROR (gettext ("\ |
| 758 | section [%2d] '%s': symbol %zu: unknown symbol binding\n"), |
| 759 | idx, section_name (ebl, idx), cnt); |
| 760 | if (GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE |
| 761 | && GELF_ST_TYPE (sym->st_info) != STT_OBJECT) |
| 762 | ERROR (gettext ("\ |
| 763 | section [%2d] '%s': symbol %zu: unique symbol not of object type\n"), |
| 764 | idx, section_name (ebl, idx), cnt); |
| 765 | |
| 766 | if (xndx == SHN_COMMON) |
| 767 | { |
| 768 | /* Common symbols can only appear in relocatable files. */ |
| 769 | if (ehdr->e_type != ET_REL) |
| 770 | ERROR (gettext ("\ |
| 771 | section [%2d] '%s': symbol %zu: COMMON only allowed in relocatable files\n"), |
| 772 | idx, section_name (ebl, idx), cnt); |
| 773 | if (cnt < shdr->sh_info) |
| 774 | ERROR (gettext ("\ |
| 775 | section [%2d] '%s': symbol %zu: local COMMON symbols are nonsense\n"), |
| 776 | idx, section_name (ebl, idx), cnt); |
| 777 | if (GELF_R_TYPE (sym->st_info) == STT_FUNC) |
| 778 | ERROR (gettext ("\ |
| 779 | section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"), |
| 780 | idx, section_name (ebl, idx), cnt); |
| 781 | } |
| 782 | else if (xndx > 0 && xndx < shnum) |
| 783 | { |
| 784 | GElf_Shdr destshdr_mem; |
| 785 | GElf_Shdr *destshdr; |
| 786 | |
| 787 | destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), &destshdr_mem); |
| 788 | if (destshdr != NULL) |
| 789 | { |
| 790 | GElf_Addr sh_addr = (ehdr->e_type == ET_REL ? 0 |
| 791 | : destshdr->sh_addr); |
| 792 | GElf_Addr st_value; |
| 793 | if (GELF_ST_TYPE (sym->st_info) == STT_FUNC |
| 794 | || (GELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)) |
| 795 | st_value = sym->st_value & ebl_func_addr_mask (ebl); |
| 796 | else |
| 797 | st_value = sym->st_value; |
| 798 | if (GELF_ST_TYPE (sym->st_info) != STT_TLS) |
| 799 | { |
| 800 | if (! ebl_check_special_symbol (ebl, ehdr, sym, name, |
| 801 | destshdr)) |
| 802 | { |
| 803 | if (st_value - sh_addr > destshdr->sh_size) |
| 804 | { |
| 805 | /* GNU ld has severe bugs. When it decides to remove |
| 806 | empty sections it leaves symbols referencing them |
| 807 | behind. These are symbols in .symtab or .dynsym |
| 808 | and for the named symbols have zero size. See |
| 809 | sourceware PR13621. */ |
| 810 | if (!gnuld |
| 811 | || (strcmp (section_name (ebl, idx), ".symtab") |
| 812 | && strcmp (section_name (ebl, idx), |
| 813 | ".dynsym")) |
| 814 | || sym->st_size != 0 |
| 815 | || (strcmp (name, "__preinit_array_start") != 0 |
| 816 | && strcmp (name, "__preinit_array_end") != 0 |
| 817 | && strcmp (name, "__init_array_start") != 0 |
| 818 | && strcmp (name, "__init_array_end") != 0 |
| 819 | && strcmp (name, "__fini_array_start") != 0 |
| 820 | && strcmp (name, "__fini_array_end") != 0 |
| 821 | && strcmp (name, "__bss_start") != 0 |
| 822 | && strcmp (name, "__bss_start__") != 0 |
| 823 | && strcmp (name, "__TMC_END__") != 0 |
| 824 | && strcmp (name, ".TOC.") != 0 |
| 825 | && strcmp (name, "_edata") != 0 |
| 826 | && strcmp (name, "__edata") != 0 |
| 827 | && strcmp (name, "_end") != 0 |
| 828 | && strcmp (name, "__end") != 0)) |
| 829 | ERROR (gettext ("\ |
| 830 | section [%2d] '%s': symbol %zu: st_value out of bounds\n"), |
| 831 | idx, section_name (ebl, idx), cnt); |
| 832 | } |
| 833 | else if ((st_value - sh_addr |
| 834 | + sym->st_size) > destshdr->sh_size) |
| 835 | ERROR (gettext ("\ |
| 836 | section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), |
| 837 | idx, section_name (ebl, idx), cnt, |
| 838 | (int) xndx, section_name (ebl, xndx)); |
| 839 | } |
| 840 | } |
| 841 | else |
| 842 | { |
| 843 | if ((destshdr->sh_flags & SHF_TLS) == 0) |
| 844 | ERROR (gettext ("\ |
| 845 | section [%2d] '%s': symbol %zu: referenced section [%2d] '%s' does not have SHF_TLS flag set\n"), |
| 846 | idx, section_name (ebl, idx), cnt, |
| 847 | (int) xndx, section_name (ebl, xndx)); |
| 848 | |
| 849 | if (ehdr->e_type == ET_REL) |
| 850 | { |
| 851 | /* For object files the symbol value must fall |
| 852 | into the section. */ |
| 853 | if (st_value > destshdr->sh_size) |
| 854 | ERROR (gettext ("\ |
| 855 | section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), |
| 856 | idx, section_name (ebl, idx), cnt, |
| 857 | (int) xndx, section_name (ebl, xndx)); |
| 858 | else if (st_value + sym->st_size |
| 859 | > destshdr->sh_size) |
| 860 | ERROR (gettext ("\ |
| 861 | section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), |
| 862 | idx, section_name (ebl, idx), cnt, |
| 863 | (int) xndx, section_name (ebl, xndx)); |
| 864 | } |
| 865 | else |
| 866 | { |
| 867 | GElf_Phdr phdr_mem; |
| 868 | GElf_Phdr *phdr = NULL; |
| 869 | unsigned int pcnt; |
| 870 | |
| 871 | for (pcnt = 0; pcnt < phnum; ++pcnt) |
| 872 | { |
| 873 | phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); |
| 874 | if (phdr != NULL && phdr->p_type == PT_TLS) |
| 875 | break; |
| 876 | } |
| 877 | |
| 878 | if (pcnt == phnum) |
| 879 | { |
| 880 | if (no_pt_tls++ == 0) |
| 881 | ERROR (gettext ("\ |
| 882 | section [%2d] '%s': symbol %zu: TLS symbol but no TLS program header entry\n"), |
| 883 | idx, section_name (ebl, idx), cnt); |
| 884 | } |
| 885 | else if (phdr == NULL) |
| 886 | { |
| 887 | ERROR (gettext ("\ |
| 888 | section [%2d] '%s': symbol %zu: TLS symbol but couldn't get TLS program header entry\n"), |
| 889 | idx, section_name (ebl, idx), cnt); |
| 890 | } |
| 891 | else if (!is_debuginfo) |
| 892 | { |
| 893 | if (st_value |
| 894 | < destshdr->sh_offset - phdr->p_offset) |
| 895 | ERROR (gettext ("\ |
| 896 | section [%2d] '%s': symbol %zu: st_value short of referenced section [%2d] '%s'\n"), |
| 897 | idx, section_name (ebl, idx), cnt, |
| 898 | (int) xndx, section_name (ebl, xndx)); |
| 899 | else if (st_value |
| 900 | > (destshdr->sh_offset - phdr->p_offset |
| 901 | + destshdr->sh_size)) |
| 902 | ERROR (gettext ("\ |
| 903 | section [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"), |
| 904 | idx, section_name (ebl, idx), cnt, |
| 905 | (int) xndx, section_name (ebl, xndx)); |
| 906 | else if (st_value + sym->st_size |
| 907 | > (destshdr->sh_offset - phdr->p_offset |
| 908 | + destshdr->sh_size)) |
| 909 | ERROR (gettext ("\ |
| 910 | section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"), |
| 911 | idx, section_name (ebl, idx), cnt, |
| 912 | (int) xndx, section_name (ebl, xndx)); |
| 913 | } |
| 914 | } |
| 915 | } |
| 916 | } |
| 917 | } |
| 918 | |
| 919 | if (GELF_ST_BIND (sym->st_info) == STB_LOCAL) |
| 920 | { |
| 921 | if (cnt >= shdr->sh_info) |
| 922 | ERROR (gettext ("\ |
| 923 | section [%2d] '%s': symbol %zu: local symbol outside range described in sh_info\n"), |
| 924 | idx, section_name (ebl, idx), cnt); |
| 925 | } |
| 926 | else |
| 927 | { |
| 928 | if (cnt < shdr->sh_info) |
| 929 | ERROR (gettext ("\ |
| 930 | section [%2d] '%s': symbol %zu: non-local symbol outside range described in sh_info\n"), |
| 931 | idx, section_name (ebl, idx), cnt); |
| 932 | } |
| 933 | |
| 934 | if (GELF_ST_TYPE (sym->st_info) == STT_SECTION |
| 935 | && GELF_ST_BIND (sym->st_info) != STB_LOCAL) |
| 936 | ERROR (gettext ("\ |
| 937 | section [%2d] '%s': symbol %zu: non-local section symbol\n"), |
| 938 | idx, section_name (ebl, idx), cnt); |
| 939 | |
| 940 | if (name != NULL) |
| 941 | { |
| 942 | if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) |
| 943 | { |
| 944 | /* Check that address and size match the global offset table. */ |
| 945 | |
| 946 | GElf_Shdr destshdr_mem; |
| 947 | GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), |
| 948 | &destshdr_mem); |
| 949 | |
| 950 | if (destshdr == NULL && xndx == SHN_ABS) |
| 951 | { |
| 952 | /* In a DSO, we have to find the GOT section by name. */ |
| 953 | Elf_Scn *gotscn = NULL; |
| 954 | Elf_Scn *gscn = NULL; |
| 955 | while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL) |
| 956 | { |
| 957 | destshdr = gelf_getshdr (gscn, &destshdr_mem); |
| 958 | assert (destshdr != NULL); |
| 959 | const char *sname = elf_strptr (ebl->elf, |
| 960 | ehdr->e_shstrndx, |
| 961 | destshdr->sh_name); |
| 962 | if (sname != NULL) |
| 963 | { |
| 964 | if (strcmp (sname, ".got.plt") == 0) |
| 965 | break; |
| 966 | if (strcmp (sname, ".got") == 0) |
| 967 | /* Do not stop looking. |
| 968 | There might be a .got.plt section. */ |
| 969 | gotscn = gscn; |
| 970 | } |
| 971 | |
| 972 | destshdr = NULL; |
| 973 | } |
| 974 | |
| 975 | if (destshdr == NULL && gotscn != NULL) |
| 976 | destshdr = gelf_getshdr (gotscn, &destshdr_mem); |
| 977 | } |
| 978 | |
| 979 | const char *sname = ((destshdr == NULL || xndx == SHN_UNDEF) |
| 980 | ? NULL |
| 981 | : elf_strptr (ebl->elf, ehdr->e_shstrndx, |
| 982 | destshdr->sh_name)); |
| 983 | if (sname == NULL) |
| 984 | { |
| 985 | if (xndx != SHN_UNDEF || ehdr->e_type != ET_REL) |
| 986 | ERROR (gettext ("\ |
| 987 | section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \ |
| 988 | bad section [%2d]\n"), |
| 989 | idx, section_name (ebl, idx), xndx); |
| 990 | } |
| 991 | else if (strcmp (sname, ".got.plt") != 0 |
| 992 | && strcmp (sname, ".got") != 0) |
| 993 | ERROR (gettext ("\ |
| 994 | section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \ |
| 995 | section [%2d] '%s'\n"), |
| 996 | idx, section_name (ebl, idx), xndx, sname); |
| 997 | |
| 998 | if (destshdr != NULL) |
| 999 | { |
| 1000 | /* Found it. */ |
| 1001 | if (!ebl_check_special_symbol (ebl, ehdr, sym, name, |
| 1002 | destshdr)) |
| 1003 | { |
| 1004 | if (ehdr->e_type != ET_REL |
| 1005 | && sym->st_value != destshdr->sh_addr) |
| 1006 | /* This test is more strict than the psABIs which |
| 1007 | usually allow the symbol to be in the middle of |
| 1008 | the .got section, allowing negative offsets. */ |
| 1009 | ERROR (gettext ("\ |
| 1010 | section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match %s section address %#" PRIx64 "\n"), |
| 1011 | idx, section_name (ebl, idx), |
| 1012 | (uint64_t) sym->st_value, |
| 1013 | sname, (uint64_t) destshdr->sh_addr); |
| 1014 | |
| 1015 | if (!gnuld && sym->st_size != destshdr->sh_size) |
| 1016 | ERROR (gettext ("\ |
| 1017 | section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match %s section size %" PRIu64 "\n"), |
| 1018 | idx, section_name (ebl, idx), |
| 1019 | (uint64_t) sym->st_size, |
| 1020 | sname, (uint64_t) destshdr->sh_size); |
| 1021 | } |
| 1022 | } |
| 1023 | else |
| 1024 | ERROR (gettext ("\ |
| 1025 | section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol present, but no .got section\n"), |
| 1026 | idx, section_name (ebl, idx)); |
| 1027 | } |
| 1028 | else if (strcmp (name, "_DYNAMIC") == 0) |
| 1029 | /* Check that address and size match the dynamic section. |
| 1030 | We locate the dynamic section via the program header |
| 1031 | entry. */ |
| 1032 | for (unsigned int pcnt = 0; pcnt < phnum; ++pcnt) |
| 1033 | { |
| 1034 | GElf_Phdr phdr_mem; |
| 1035 | GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); |
| 1036 | |
| 1037 | if (phdr != NULL && phdr->p_type == PT_DYNAMIC) |
| 1038 | { |
| 1039 | if (sym->st_value != phdr->p_vaddr) |
| 1040 | ERROR (gettext ("\ |
| 1041 | section [%2d] '%s': _DYNAMIC_ symbol value %#" PRIx64 " does not match dynamic segment address %#" PRIx64 "\n"), |
| 1042 | idx, section_name (ebl, idx), |
| 1043 | (uint64_t) sym->st_value, |
| 1044 | (uint64_t) phdr->p_vaddr); |
| 1045 | |
| 1046 | if (!gnuld && sym->st_size != phdr->p_memsz) |
| 1047 | ERROR (gettext ("\ |
| 1048 | section [%2d] '%s': _DYNAMIC symbol size %" PRIu64 " does not match dynamic segment size %" PRIu64 "\n"), |
| 1049 | idx, section_name (ebl, idx), |
| 1050 | (uint64_t) sym->st_size, |
| 1051 | (uint64_t) phdr->p_memsz); |
| 1052 | |
| 1053 | break; |
| 1054 | } |
| 1055 | } |
| 1056 | } |
| 1057 | |
| 1058 | if (GELF_ST_VISIBILITY (sym->st_other) != STV_DEFAULT |
| 1059 | && shdr->sh_type == SHT_DYNSYM) |
| 1060 | ERROR (gettext ("\ |
| 1061 | section [%2d] '%s': symbol %zu: symbol in dynamic symbol table with non-default visibility\n"), |
| 1062 | idx, section_name (ebl, idx), cnt); |
| 1063 | if (! ebl_check_st_other_bits (ebl, sym->st_other)) |
| 1064 | ERROR (gettext ("\ |
| 1065 | section [%2d] '%s': symbol %zu: unknown bit set in st_other\n"), |
| 1066 | idx, section_name (ebl, idx), cnt); |
| 1067 | |
| 1068 | } |
| 1069 | } |
| 1070 | |
| 1071 | |
| 1072 | static bool |
| 1073 | is_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr, |
| 1074 | bool is_rela) |
| 1075 | { |
| 1076 | /* If this is no executable or DSO it cannot be a .rel.dyn section. */ |
| 1077 | if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) |
| 1078 | return false; |
| 1079 | |
| 1080 | /* Check the section name. Unfortunately necessary. */ |
| 1081 | if (strcmp (section_name (ebl, idx), is_rela ? ".rela.dyn" : ".rel.dyn")) |
| 1082 | return false; |
| 1083 | |
| 1084 | /* When a .rel.dyn section is used a DT_RELCOUNT dynamic section |
| 1085 | entry can be present as well. */ |
| 1086 | Elf_Scn *scn = NULL; |
| 1087 | while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) |
| 1088 | { |
| 1089 | GElf_Shdr rcshdr_mem; |
| 1090 | const GElf_Shdr *rcshdr = gelf_getshdr (scn, &rcshdr_mem); |
| 1091 | |
| 1092 | if (rcshdr == NULL) |
| 1093 | break; |
| 1094 | |
| 1095 | if (rcshdr->sh_type == SHT_DYNAMIC && rcshdr->sh_entsize != 0) |
| 1096 | { |
| 1097 | /* Found the dynamic section. Look through it. */ |
| 1098 | Elf_Data *d = elf_getdata (scn, NULL); |
| 1099 | size_t cnt; |
| 1100 | |
| 1101 | if (d == NULL) |
| 1102 | ERROR (gettext ("\ |
| 1103 | section [%2d] '%s': cannot get section data.\n"), |
| 1104 | idx, section_name (ebl, idx)); |
| 1105 | |
| 1106 | for (cnt = 1; cnt < rcshdr->sh_size / rcshdr->sh_entsize; ++cnt) |
| 1107 | { |
| 1108 | GElf_Dyn dyn_mem; |
| 1109 | GElf_Dyn *dyn = gelf_getdyn (d, cnt, &dyn_mem); |
| 1110 | |
| 1111 | if (dyn == NULL) |
| 1112 | break; |
| 1113 | |
| 1114 | if (dyn->d_tag == DT_RELCOUNT) |
| 1115 | { |
| 1116 | /* Found it. Does the type match. */ |
| 1117 | if (is_rela) |
| 1118 | ERROR (gettext ("\ |
| 1119 | section [%2d] '%s': DT_RELCOUNT used for this RELA section\n"), |
| 1120 | idx, section_name (ebl, idx)); |
| 1121 | else |
| 1122 | { |
| 1123 | /* Does the number specified number of relative |
| 1124 | relocations exceed the total number of |
| 1125 | relocations? */ |
| 1126 | if (shdr->sh_entsize != 0 |
| 1127 | && dyn->d_un.d_val > (shdr->sh_size |
| 1128 | / shdr->sh_entsize)) |
| 1129 | ERROR (gettext ("\ |
| 1130 | section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), |
| 1131 | idx, section_name (ebl, idx), |
| 1132 | (int) dyn->d_un.d_val); |
| 1133 | |
| 1134 | /* Make sure the specified number of relocations are |
| 1135 | relative. */ |
| 1136 | Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf, |
| 1137 | idx), NULL); |
| 1138 | if (reldata != NULL && shdr->sh_entsize != 0) |
| 1139 | for (size_t inner = 0; |
| 1140 | inner < shdr->sh_size / shdr->sh_entsize; |
| 1141 | ++inner) |
| 1142 | { |
| 1143 | GElf_Rel rel_mem; |
| 1144 | GElf_Rel *rel = gelf_getrel (reldata, inner, |
| 1145 | &rel_mem); |
| 1146 | if (rel == NULL) |
| 1147 | /* The problem will be reported elsewhere. */ |
| 1148 | break; |
| 1149 | |
| 1150 | if (ebl_relative_reloc_p (ebl, |
| 1151 | GELF_R_TYPE (rel->r_info))) |
| 1152 | { |
| 1153 | if (inner >= dyn->d_un.d_val) |
| 1154 | ERROR (gettext ("\ |
| 1155 | section [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"), |
| 1156 | idx, section_name (ebl, idx), |
| 1157 | (int) dyn->d_un.d_val); |
| 1158 | } |
| 1159 | else if (inner < dyn->d_un.d_val) |
| 1160 | ERROR (gettext ("\ |
| 1161 | section [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"), |
| 1162 | idx, section_name (ebl, idx), |
| 1163 | inner, (int) dyn->d_un.d_val); |
| 1164 | } |
| 1165 | } |
| 1166 | } |
| 1167 | |
| 1168 | if (dyn->d_tag == DT_RELACOUNT) |
| 1169 | { |
| 1170 | /* Found it. Does the type match. */ |
| 1171 | if (!is_rela) |
| 1172 | ERROR (gettext ("\ |
| 1173 | section [%2d] '%s': DT_RELACOUNT used for this REL section\n"), |
| 1174 | idx, section_name (ebl, idx)); |
| 1175 | else |
| 1176 | { |
| 1177 | /* Does the number specified number of relative |
| 1178 | relocations exceed the total number of |
| 1179 | relocations? */ |
| 1180 | if (shdr->sh_entsize != 0 |
| 1181 | && dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize) |
| 1182 | ERROR (gettext ("\ |
| 1183 | section [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"), |
| 1184 | idx, section_name (ebl, idx), |
| 1185 | (int) dyn->d_un.d_val); |
| 1186 | |
| 1187 | /* Make sure the specified number of relocations are |
| 1188 | relative. */ |
| 1189 | Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf, |
| 1190 | idx), NULL); |
| 1191 | if (reldata != NULL && shdr->sh_entsize != 0) |
| 1192 | for (size_t inner = 0; |
| 1193 | inner < shdr->sh_size / shdr->sh_entsize; |
| 1194 | ++inner) |
| 1195 | { |
| 1196 | GElf_Rela rela_mem; |
| 1197 | GElf_Rela *rela = gelf_getrela (reldata, inner, |
| 1198 | &rela_mem); |
| 1199 | if (rela == NULL) |
| 1200 | /* The problem will be reported elsewhere. */ |
| 1201 | break; |
| 1202 | |
| 1203 | if (ebl_relative_reloc_p (ebl, |
| 1204 | GELF_R_TYPE (rela->r_info))) |
| 1205 | { |
| 1206 | if (inner >= dyn->d_un.d_val) |
| 1207 | ERROR (gettext ("\ |
| 1208 | section [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"), |
| 1209 | idx, section_name (ebl, idx), |
| 1210 | (int) dyn->d_un.d_val); |
| 1211 | } |
| 1212 | else if (inner < dyn->d_un.d_val) |
| 1213 | ERROR (gettext ("\ |
| 1214 | section [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"), |
| 1215 | idx, section_name (ebl, idx), |
| 1216 | inner, (int) dyn->d_un.d_val); |
| 1217 | } |
| 1218 | } |
| 1219 | } |
| 1220 | } |
| 1221 | |
| 1222 | break; |
| 1223 | } |
| 1224 | } |
| 1225 | |
| 1226 | return true; |
| 1227 | } |
| 1228 | |
| 1229 | |
| 1230 | struct loaded_segment |
| 1231 | { |
| 1232 | GElf_Addr from; |
| 1233 | GElf_Addr to; |
| 1234 | bool read_only; |
| 1235 | struct loaded_segment *next; |
| 1236 | }; |
| 1237 | |
| 1238 | |
| 1239 | /* Check whether binary has text relocation flag set. */ |
| 1240 | static bool textrel; |
| 1241 | |
| 1242 | /* Keep track of whether text relocation flag is needed. */ |
| 1243 | static bool needed_textrel; |
| 1244 | |
| 1245 | |
| 1246 | static bool |
| 1247 | check_reloc_shdr (Ebl *ebl, const GElf_Ehdr *ehdr, const GElf_Shdr *shdr, |
| 1248 | int idx, int reltype, GElf_Shdr **destshdrp, |
| 1249 | GElf_Shdr *destshdr_memp, struct loaded_segment **loadedp) |
| 1250 | { |
| 1251 | bool reldyn = false; |
| 1252 | |
| 1253 | /* Check whether the link to the section we relocate is reasonable. */ |
| 1254 | if (shdr->sh_info >= shnum) |
| 1255 | ERROR (gettext ("section [%2d] '%s': invalid destination section index\n"), |
| 1256 | idx, section_name (ebl, idx)); |
| 1257 | else if (shdr->sh_info != 0) |
| 1258 | { |
| 1259 | *destshdrp = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info), |
| 1260 | destshdr_memp); |
| 1261 | if (*destshdrp != NULL) |
| 1262 | { |
| 1263 | if(! ebl_check_reloc_target_type (ebl, (*destshdrp)->sh_type)) |
| 1264 | { |
| 1265 | reldyn = is_rel_dyn (ebl, ehdr, idx, shdr, true); |
| 1266 | if (!reldyn) |
| 1267 | ERROR (gettext ("\ |
| 1268 | section [%2d] '%s': invalid destination section type\n"), |
| 1269 | idx, section_name (ebl, idx)); |
| 1270 | else |
| 1271 | { |
| 1272 | /* There is no standard, but we require that .rel{,a}.dyn |
| 1273 | sections have a sh_info value of zero. */ |
| 1274 | if (shdr->sh_info != 0) |
| 1275 | ERROR (gettext ("\ |
| 1276 | section [%2d] '%s': sh_info should be zero\n"), |
| 1277 | idx, section_name (ebl, idx)); |
| 1278 | } |
| 1279 | } |
| 1280 | |
| 1281 | if ((((*destshdrp)->sh_flags & SHF_MERGE) != 0) |
| 1282 | && ((*destshdrp)->sh_flags & SHF_STRINGS) != 0) |
| 1283 | ERROR (gettext ("\ |
| 1284 | section [%2d] '%s': no relocations for merge-able string sections possible\n"), |
| 1285 | idx, section_name (ebl, idx)); |
| 1286 | } |
| 1287 | } |
| 1288 | |
| 1289 | size_t sh_entsize = gelf_fsize (ebl->elf, reltype, 1, EV_CURRENT); |
| 1290 | if (shdr->sh_entsize != sh_entsize) |
| 1291 | ERROR (gettext (reltype == ELF_T_RELA ? "\ |
| 1292 | section [%2d] '%s': section entry size does not match ElfXX_Rela\n" : "\ |
| 1293 | section [%2d] '%s': section entry size does not match ElfXX_Rel\n"), |
| 1294 | idx, section_name (ebl, idx)); |
| 1295 | |
| 1296 | /* In preparation of checking whether relocations are text |
| 1297 | relocations or not we need to determine whether the file is |
| 1298 | flagged to have text relocation and we need to determine a) what |
| 1299 | the loaded segments are and b) which are read-only. This will |
| 1300 | also allow us to determine whether the same reloc section is |
| 1301 | modifying loaded and not loaded segments. */ |
| 1302 | for (unsigned int i = 0; i < phnum; ++i) |
| 1303 | { |
| 1304 | GElf_Phdr phdr_mem; |
| 1305 | GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem); |
| 1306 | if (phdr == NULL) |
| 1307 | continue; |
| 1308 | |
| 1309 | if (phdr->p_type == PT_LOAD) |
| 1310 | { |
| 1311 | struct loaded_segment *newp = xmalloc (sizeof (*newp)); |
| 1312 | newp->from = phdr->p_vaddr; |
| 1313 | newp->to = phdr->p_vaddr + phdr->p_memsz; |
| 1314 | newp->read_only = (phdr->p_flags & PF_W) == 0; |
| 1315 | newp->next = *loadedp; |
| 1316 | *loadedp = newp; |
| 1317 | } |
| 1318 | else if (phdr->p_type == PT_DYNAMIC) |
| 1319 | { |
| 1320 | Elf_Scn *dynscn = gelf_offscn (ebl->elf, phdr->p_offset); |
| 1321 | GElf_Shdr dynshdr_mem; |
| 1322 | GElf_Shdr *dynshdr = gelf_getshdr (dynscn, &dynshdr_mem); |
| 1323 | Elf_Data *dyndata = elf_getdata (dynscn, NULL); |
| 1324 | if (dynshdr != NULL && dynshdr->sh_type == SHT_DYNAMIC |
| 1325 | && dyndata != NULL && dynshdr->sh_entsize != 0) |
| 1326 | for (size_t j = 0; j < dynshdr->sh_size / dynshdr->sh_entsize; ++j) |
| 1327 | { |
| 1328 | GElf_Dyn dyn_mem; |
| 1329 | GElf_Dyn *dyn = gelf_getdyn (dyndata, j, &dyn_mem); |
| 1330 | if (dyn != NULL |
| 1331 | && (dyn->d_tag == DT_TEXTREL |
| 1332 | || (dyn->d_tag == DT_FLAGS |
| 1333 | && (dyn->d_un.d_val & DF_TEXTREL) != 0))) |
| 1334 | { |
| 1335 | textrel = true; |
| 1336 | break; |
| 1337 | } |
| 1338 | } |
| 1339 | } |
| 1340 | } |
| 1341 | |
| 1342 | /* A quick test which can be easily done here (although it is a bit |
| 1343 | out of place): the text relocation flag makes only sense if there |
| 1344 | is a segment which is not writable. */ |
| 1345 | if (textrel) |
| 1346 | { |
| 1347 | struct loaded_segment *seg = *loadedp; |
| 1348 | while (seg != NULL && !seg->read_only) |
| 1349 | seg = seg->next; |
| 1350 | if (seg == NULL) |
| 1351 | ERROR (gettext ("\ |
| 1352 | text relocation flag set but there is no read-only segment\n")); |
| 1353 | } |
| 1354 | |
| 1355 | return reldyn; |
| 1356 | } |
| 1357 | |
| 1358 | |
| 1359 | enum load_state |
| 1360 | { |
| 1361 | state_undecided, |
| 1362 | state_loaded, |
| 1363 | state_unloaded, |
| 1364 | state_error |
| 1365 | }; |
| 1366 | |
| 1367 | |
| 1368 | static void |
| 1369 | check_one_reloc (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *relshdr, int idx, |
| 1370 | size_t cnt, const GElf_Shdr *symshdr, Elf_Data *symdata, |
| 1371 | GElf_Addr r_offset, GElf_Xword r_info, |
| 1372 | const GElf_Shdr *destshdr, bool reldyn, |
| 1373 | struct loaded_segment *loaded, enum load_state *statep) |
| 1374 | { |
| 1375 | bool known_broken = gnuld; |
| 1376 | |
| 1377 | if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (r_info))) |
| 1378 | ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"), |
| 1379 | idx, section_name (ebl, idx), cnt); |
| 1380 | else if (((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) |
| 1381 | /* The executable/DSO can contain relocation sections with |
| 1382 | all the relocations the linker has applied. Those sections |
| 1383 | are marked non-loaded, though. */ |
| 1384 | || (relshdr->sh_flags & SHF_ALLOC) != 0) |
| 1385 | && !ebl_reloc_valid_use (ebl, GELF_R_TYPE (r_info))) |
| 1386 | ERROR (gettext ("\ |
| 1387 | section [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"), |
| 1388 | idx, section_name (ebl, idx), cnt); |
| 1389 | |
| 1390 | if (symshdr != NULL |
| 1391 | && ((GELF_R_SYM (r_info) + 1) |
| 1392 | * gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT) |
| 1393 | > symshdr->sh_size)) |
| 1394 | ERROR (gettext ("\ |
| 1395 | section [%2d] '%s': relocation %zu: invalid symbol index\n"), |
| 1396 | idx, section_name (ebl, idx), cnt); |
| 1397 | |
| 1398 | /* No more tests if this is a no-op relocation. */ |
| 1399 | if (ebl_none_reloc_p (ebl, GELF_R_TYPE (r_info))) |
| 1400 | return; |
| 1401 | |
| 1402 | if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (r_info))) |
| 1403 | { |
| 1404 | const char *name; |
| 1405 | char buf[64]; |
| 1406 | GElf_Sym sym_mem; |
| 1407 | GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (r_info), &sym_mem); |
| 1408 | if (sym != NULL |
| 1409 | /* Get the name for the symbol. */ |
| 1410 | && (name = elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name)) |
| 1411 | && strcmp (name, "_GLOBAL_OFFSET_TABLE_") !=0 ) |
| 1412 | ERROR (gettext ("\ |
| 1413 | section [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be used with %s\n"), |
| 1414 | idx, section_name (ebl, idx), cnt, |
| 1415 | ebl_reloc_type_name (ebl, GELF_R_SYM (r_info), |
| 1416 | buf, sizeof (buf))); |
| 1417 | } |
| 1418 | |
| 1419 | if (reldyn) |
| 1420 | { |
| 1421 | // XXX TODO Check .rel.dyn section addresses. |
| 1422 | } |
| 1423 | else if (!known_broken) |
| 1424 | { |
| 1425 | if (destshdr != NULL |
| 1426 | && GELF_R_TYPE (r_info) != 0 |
| 1427 | && (r_offset - (ehdr->e_type == ET_REL ? 0 |
| 1428 | : destshdr->sh_addr)) >= destshdr->sh_size) |
| 1429 | ERROR (gettext ("\ |
| 1430 | section [%2d] '%s': relocation %zu: offset out of bounds\n"), |
| 1431 | idx, section_name (ebl, idx), cnt); |
| 1432 | } |
| 1433 | |
| 1434 | GElf_Sym sym_mem; |
| 1435 | GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (r_info), &sym_mem); |
| 1436 | |
| 1437 | if (ebl_copy_reloc_p (ebl, GELF_R_TYPE (r_info)) |
| 1438 | /* Make sure the referenced symbol is an object or unspecified. */ |
| 1439 | && sym != NULL |
| 1440 | && GELF_ST_TYPE (sym->st_info) != STT_NOTYPE |
| 1441 | && GELF_ST_TYPE (sym->st_info) != STT_OBJECT) |
| 1442 | { |
| 1443 | char buf[64]; |
| 1444 | ERROR (gettext ("section [%2d] '%s': relocation %zu: copy relocation against symbol of type %s\n"), |
| 1445 | idx, section_name (ebl, idx), cnt, |
| 1446 | ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), |
| 1447 | buf, sizeof (buf))); |
| 1448 | } |
| 1449 | |
| 1450 | if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) |
| 1451 | || (relshdr->sh_flags & SHF_ALLOC) != 0) |
| 1452 | { |
| 1453 | bool in_loaded_seg = false; |
| 1454 | while (loaded != NULL) |
| 1455 | { |
| 1456 | if (r_offset < loaded->to |
| 1457 | && r_offset + (sym == NULL ? 0 : sym->st_size) >= loaded->from) |
| 1458 | { |
| 1459 | /* The symbol is in this segment. */ |
| 1460 | if (loaded->read_only) |
| 1461 | { |
| 1462 | if (textrel) |
| 1463 | needed_textrel = true; |
| 1464 | else |
| 1465 | ERROR (gettext ("section [%2d] '%s': relocation %zu: read-only section modified but text relocation flag not set\n"), |
| 1466 | idx, section_name (ebl, idx), cnt); |
| 1467 | } |
| 1468 | |
| 1469 | in_loaded_seg = true; |
| 1470 | } |
| 1471 | |
| 1472 | loaded = loaded->next; |
| 1473 | } |
| 1474 | |
| 1475 | if (*statep == state_undecided) |
| 1476 | *statep = in_loaded_seg ? state_loaded : state_unloaded; |
| 1477 | else if ((*statep == state_unloaded && in_loaded_seg) |
| 1478 | || (*statep == state_loaded && !in_loaded_seg)) |
| 1479 | { |
| 1480 | ERROR (gettext ("\ |
| 1481 | section [%2d] '%s': relocations are against loaded and unloaded data\n"), |
| 1482 | idx, section_name (ebl, idx)); |
| 1483 | *statep = state_error; |
| 1484 | } |
| 1485 | } |
| 1486 | } |
| 1487 | |
| 1488 | |
| 1489 | static void |
| 1490 | check_rela (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 1491 | { |
| 1492 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 1493 | if (data == NULL) |
| 1494 | { |
| 1495 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 1496 | idx, section_name (ebl, idx)); |
| 1497 | return; |
| 1498 | } |
| 1499 | |
| 1500 | /* Check the fields of the section header. */ |
| 1501 | GElf_Shdr destshdr_mem; |
| 1502 | GElf_Shdr *destshdr = NULL; |
| 1503 | struct loaded_segment *loaded = NULL; |
| 1504 | bool reldyn = check_reloc_shdr (ebl, ehdr, shdr, idx, ELF_T_RELA, &destshdr, |
| 1505 | &destshdr_mem, &loaded); |
| 1506 | |
| 1507 | Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); |
| 1508 | GElf_Shdr symshdr_mem; |
| 1509 | GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); |
| 1510 | Elf_Data *symdata = elf_getdata (symscn, NULL); |
| 1511 | enum load_state state = state_undecided; |
| 1512 | |
| 1513 | size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_RELA, 1, EV_CURRENT); |
| 1514 | for (size_t cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt) |
| 1515 | { |
| 1516 | GElf_Rela rela_mem; |
| 1517 | GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem); |
| 1518 | if (rela == NULL) |
| 1519 | { |
| 1520 | ERROR (gettext ("\ |
| 1521 | section [%2d] '%s': cannot get relocation %zu: %s\n"), |
| 1522 | idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); |
| 1523 | continue; |
| 1524 | } |
| 1525 | |
| 1526 | check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata, |
| 1527 | rela->r_offset, rela->r_info, destshdr, reldyn, loaded, |
| 1528 | &state); |
| 1529 | } |
| 1530 | |
| 1531 | while (loaded != NULL) |
| 1532 | { |
| 1533 | struct loaded_segment *old = loaded; |
| 1534 | loaded = loaded->next; |
| 1535 | free (old); |
| 1536 | } |
| 1537 | } |
| 1538 | |
| 1539 | |
| 1540 | static void |
| 1541 | check_rel (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 1542 | { |
| 1543 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 1544 | if (data == NULL) |
| 1545 | { |
| 1546 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 1547 | idx, section_name (ebl, idx)); |
| 1548 | return; |
| 1549 | } |
| 1550 | |
| 1551 | /* Check the fields of the section header. */ |
| 1552 | GElf_Shdr destshdr_mem; |
| 1553 | GElf_Shdr *destshdr = NULL; |
| 1554 | struct loaded_segment *loaded = NULL; |
| 1555 | bool reldyn = check_reloc_shdr (ebl, ehdr, shdr, idx, ELF_T_REL, &destshdr, |
| 1556 | &destshdr_mem, &loaded); |
| 1557 | |
| 1558 | Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); |
| 1559 | GElf_Shdr symshdr_mem; |
| 1560 | GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); |
| 1561 | Elf_Data *symdata = elf_getdata (symscn, NULL); |
| 1562 | enum load_state state = state_undecided; |
| 1563 | |
| 1564 | size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_REL, 1, EV_CURRENT); |
| 1565 | for (size_t cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt) |
| 1566 | { |
| 1567 | GElf_Rel rel_mem; |
| 1568 | GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem); |
| 1569 | if (rel == NULL) |
| 1570 | { |
| 1571 | ERROR (gettext ("\ |
| 1572 | section [%2d] '%s': cannot get relocation %zu: %s\n"), |
| 1573 | idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); |
| 1574 | continue; |
| 1575 | } |
| 1576 | |
| 1577 | check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata, |
| 1578 | rel->r_offset, rel->r_info, destshdr, reldyn, loaded, |
| 1579 | &state); |
| 1580 | } |
| 1581 | |
| 1582 | while (loaded != NULL) |
| 1583 | { |
| 1584 | struct loaded_segment *old = loaded; |
| 1585 | loaded = loaded->next; |
| 1586 | free (old); |
| 1587 | } |
| 1588 | } |
| 1589 | |
| 1590 | |
| 1591 | /* Number of dynamic sections. */ |
| 1592 | static int ndynamic; |
| 1593 | |
| 1594 | |
| 1595 | static void |
| 1596 | check_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 1597 | { |
| 1598 | Elf_Data *data; |
| 1599 | GElf_Shdr strshdr_mem; |
| 1600 | GElf_Shdr *strshdr; |
| 1601 | size_t cnt; |
| 1602 | static const bool dependencies[DT_NUM][DT_NUM] = |
| 1603 | { |
| 1604 | [DT_NEEDED] = { [DT_STRTAB] = true }, |
| 1605 | [DT_PLTRELSZ] = { [DT_JMPREL] = true }, |
| 1606 | [DT_HASH] = { [DT_SYMTAB] = true }, |
| 1607 | [DT_STRTAB] = { [DT_STRSZ] = true }, |
| 1608 | [DT_SYMTAB] = { [DT_STRTAB] = true, [DT_SYMENT] = true }, |
| 1609 | [DT_RELA] = { [DT_RELASZ] = true, [DT_RELAENT] = true }, |
| 1610 | [DT_RELASZ] = { [DT_RELA] = true }, |
| 1611 | [DT_RELAENT] = { [DT_RELA] = true }, |
| 1612 | [DT_STRSZ] = { [DT_STRTAB] = true }, |
| 1613 | [DT_SYMENT] = { [DT_SYMTAB] = true }, |
| 1614 | [DT_SONAME] = { [DT_STRTAB] = true }, |
| 1615 | [DT_RPATH] = { [DT_STRTAB] = true }, |
| 1616 | [DT_REL] = { [DT_RELSZ] = true, [DT_RELENT] = true }, |
| 1617 | [DT_RELSZ] = { [DT_REL] = true }, |
| 1618 | [DT_RELENT] = { [DT_REL] = true }, |
| 1619 | [DT_JMPREL] = { [DT_PLTRELSZ] = true, [DT_PLTREL] = true }, |
| 1620 | [DT_RUNPATH] = { [DT_STRTAB] = true }, |
| 1621 | [DT_PLTREL] = { [DT_JMPREL] = true }, |
| 1622 | }; |
| 1623 | bool has_dt[DT_NUM]; |
| 1624 | bool has_val_dt[DT_VALNUM]; |
| 1625 | bool has_addr_dt[DT_ADDRNUM]; |
| 1626 | static const bool level2[DT_NUM] = |
| 1627 | { |
| 1628 | [DT_RPATH] = true, |
| 1629 | [DT_SYMBOLIC] = true, |
| 1630 | [DT_TEXTREL] = true, |
| 1631 | [DT_BIND_NOW] = true |
| 1632 | }; |
| 1633 | static const bool mandatory[DT_NUM] = |
| 1634 | { |
| 1635 | [DT_NULL] = true, |
| 1636 | [DT_STRTAB] = true, |
| 1637 | [DT_SYMTAB] = true, |
| 1638 | [DT_STRSZ] = true, |
| 1639 | [DT_SYMENT] = true |
| 1640 | }; |
| 1641 | |
| 1642 | memset (has_dt, '\0', sizeof (has_dt)); |
| 1643 | memset (has_val_dt, '\0', sizeof (has_val_dt)); |
| 1644 | memset (has_addr_dt, '\0', sizeof (has_addr_dt)); |
| 1645 | |
| 1646 | if (++ndynamic == 2) |
| 1647 | ERROR (gettext ("more than one dynamic section present\n")); |
| 1648 | |
| 1649 | data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 1650 | if (data == NULL) |
| 1651 | { |
| 1652 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 1653 | idx, section_name (ebl, idx)); |
| 1654 | return; |
| 1655 | } |
| 1656 | |
| 1657 | strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &strshdr_mem); |
| 1658 | if (strshdr != NULL && strshdr->sh_type != SHT_STRTAB) |
| 1659 | ERROR (gettext ("\ |
| 1660 | section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"), |
| 1661 | shdr->sh_link, section_name (ebl, shdr->sh_link), |
| 1662 | idx, section_name (ebl, idx)); |
| 1663 | else if (strshdr == NULL) |
| 1664 | { |
| 1665 | ERROR (gettext ("\ |
| 1666 | section [%2d]: referenced as string table for section [%2d] '%s' but section link value is invalid\n"), |
| 1667 | shdr->sh_link, idx, section_name (ebl, idx)); |
| 1668 | return; |
| 1669 | } |
| 1670 | |
| 1671 | size_t sh_entsize = gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT); |
| 1672 | if (shdr->sh_entsize != sh_entsize) |
| 1673 | ERROR (gettext ("\ |
| 1674 | section [%2d] '%s': section entry size does not match ElfXX_Dyn\n"), |
| 1675 | idx, section_name (ebl, idx)); |
| 1676 | |
| 1677 | if (shdr->sh_info != 0) |
| 1678 | ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"), |
| 1679 | idx, section_name (ebl, idx)); |
| 1680 | |
| 1681 | bool non_null_warned = false; |
| 1682 | for (cnt = 0; cnt < shdr->sh_size / sh_entsize; ++cnt) |
| 1683 | { |
| 1684 | GElf_Dyn dyn_mem; |
| 1685 | GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dyn_mem); |
| 1686 | if (dyn == NULL) |
| 1687 | { |
| 1688 | ERROR (gettext ("\ |
| 1689 | section [%2d] '%s': cannot get dynamic section entry %zu: %s\n"), |
| 1690 | idx, section_name (ebl, idx), cnt, elf_errmsg (-1)); |
| 1691 | continue; |
| 1692 | } |
| 1693 | |
| 1694 | if (has_dt[DT_NULL] && dyn->d_tag != DT_NULL && ! non_null_warned) |
| 1695 | { |
| 1696 | ERROR (gettext ("\ |
| 1697 | section [%2d] '%s': non-DT_NULL entries follow DT_NULL entry\n"), |
| 1698 | idx, section_name (ebl, idx)); |
| 1699 | non_null_warned = true; |
| 1700 | } |
| 1701 | |
| 1702 | if (!ebl_dynamic_tag_check (ebl, dyn->d_tag)) |
| 1703 | ERROR (gettext ("section [%2d] '%s': entry %zu: unknown tag\n"), |
| 1704 | idx, section_name (ebl, idx), cnt); |
| 1705 | |
| 1706 | if (dyn->d_tag >= 0 && dyn->d_tag < DT_NUM) |
| 1707 | { |
| 1708 | if (has_dt[dyn->d_tag] |
| 1709 | && dyn->d_tag != DT_NEEDED |
| 1710 | && dyn->d_tag != DT_NULL |
| 1711 | && dyn->d_tag != DT_POSFLAG_1) |
| 1712 | { |
| 1713 | char buf[50]; |
| 1714 | ERROR (gettext ("\ |
| 1715 | section [%2d] '%s': entry %zu: more than one entry with tag %s\n"), |
| 1716 | idx, section_name (ebl, idx), cnt, |
| 1717 | ebl_dynamic_tag_name (ebl, dyn->d_tag, |
| 1718 | buf, sizeof (buf))); |
| 1719 | } |
| 1720 | |
| 1721 | if (be_strict && level2[dyn->d_tag]) |
| 1722 | { |
| 1723 | char buf[50]; |
| 1724 | ERROR (gettext ("\ |
| 1725 | section [%2d] '%s': entry %zu: level 2 tag %s used\n"), |
| 1726 | idx, section_name (ebl, idx), cnt, |
| 1727 | ebl_dynamic_tag_name (ebl, dyn->d_tag, |
| 1728 | buf, sizeof (buf))); |
| 1729 | } |
| 1730 | |
| 1731 | has_dt[dyn->d_tag] = true; |
| 1732 | } |
| 1733 | else if (dyn->d_tag >= 0 && dyn->d_tag <= DT_VALRNGHI |
| 1734 | && DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM) |
| 1735 | has_val_dt[DT_VALTAGIDX (dyn->d_tag)] = true; |
| 1736 | else if (dyn->d_tag >= 0 && dyn->d_tag <= DT_ADDRRNGHI |
| 1737 | && DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM) |
| 1738 | has_addr_dt[DT_ADDRTAGIDX (dyn->d_tag)] = true; |
| 1739 | |
| 1740 | if (dyn->d_tag == DT_PLTREL && dyn->d_un.d_val != DT_REL |
| 1741 | && dyn->d_un.d_val != DT_RELA) |
| 1742 | ERROR (gettext ("\ |
| 1743 | section [%2d] '%s': entry %zu: DT_PLTREL value must be DT_REL or DT_RELA\n"), |
| 1744 | idx, section_name (ebl, idx), cnt); |
| 1745 | |
| 1746 | /* Check that addresses for entries are in loaded segments. */ |
| 1747 | switch (dyn->d_tag) |
| 1748 | { |
| 1749 | size_t n; |
| 1750 | case DT_STRTAB: |
| 1751 | /* We require the referenced section is the same as the one |
| 1752 | specified in sh_link. */ |
| 1753 | if (strshdr->sh_addr != dyn->d_un.d_val) |
| 1754 | { |
| 1755 | ERROR (gettext ("\ |
| 1756 | section [%2d] '%s': entry %zu: pointer does not match address of section [%2d] '%s' referenced by sh_link\n"), |
| 1757 | idx, section_name (ebl, idx), cnt, |
| 1758 | shdr->sh_link, section_name (ebl, shdr->sh_link)); |
| 1759 | break; |
| 1760 | } |
| 1761 | goto check_addr; |
| 1762 | |
| 1763 | default: |
| 1764 | if (dyn->d_tag < DT_ADDRRNGLO || dyn->d_tag > DT_ADDRRNGHI) |
| 1765 | /* Value is no pointer. */ |
| 1766 | break; |
| 1767 | FALLTHROUGH; |
| 1768 | |
| 1769 | case DT_AUXILIARY: |
| 1770 | case DT_FILTER: |
| 1771 | case DT_FINI: |
| 1772 | case DT_FINI_ARRAY: |
| 1773 | case DT_HASH: |
| 1774 | case DT_INIT: |
| 1775 | case DT_INIT_ARRAY: |
| 1776 | case DT_JMPREL: |
| 1777 | case DT_PLTGOT: |
| 1778 | case DT_REL: |
| 1779 | case DT_RELA: |
| 1780 | case DT_SYMBOLIC: |
| 1781 | case DT_SYMTAB: |
| 1782 | case DT_VERDEF: |
| 1783 | case DT_VERNEED: |
| 1784 | case DT_VERSYM: |
| 1785 | check_addr: |
| 1786 | for (n = 0; n < phnum; ++n) |
| 1787 | { |
| 1788 | GElf_Phdr phdr_mem; |
| 1789 | GElf_Phdr *phdr = gelf_getphdr (ebl->elf, n, &phdr_mem); |
| 1790 | if (phdr != NULL && phdr->p_type == PT_LOAD |
| 1791 | && phdr->p_vaddr <= dyn->d_un.d_ptr |
| 1792 | && phdr->p_vaddr + phdr->p_memsz > dyn->d_un.d_ptr) |
| 1793 | break; |
| 1794 | } |
| 1795 | if (unlikely (n >= phnum)) |
| 1796 | { |
| 1797 | char buf[50]; |
| 1798 | ERROR (gettext ("\ |
| 1799 | section [%2d] '%s': entry %zu: %s value must point into loaded segment\n"), |
| 1800 | idx, section_name (ebl, idx), cnt, |
| 1801 | ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, |
| 1802 | sizeof (buf))); |
| 1803 | } |
| 1804 | break; |
| 1805 | |
| 1806 | case DT_NEEDED: |
| 1807 | case DT_RPATH: |
| 1808 | case DT_RUNPATH: |
| 1809 | case DT_SONAME: |
| 1810 | if (dyn->d_un.d_ptr >= strshdr->sh_size) |
| 1811 | { |
| 1812 | char buf[50]; |
| 1813 | ERROR (gettext ("\ |
| 1814 | section [%2d] '%s': entry %zu: %s value must be valid offset in section [%2d] '%s'\n"), |
| 1815 | idx, section_name (ebl, idx), cnt, |
| 1816 | ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, |
| 1817 | sizeof (buf)), |
| 1818 | shdr->sh_link, section_name (ebl, shdr->sh_link)); |
| 1819 | } |
| 1820 | break; |
| 1821 | } |
| 1822 | } |
| 1823 | |
| 1824 | for (cnt = 1; cnt < DT_NUM; ++cnt) |
| 1825 | if (has_dt[cnt]) |
| 1826 | { |
| 1827 | for (int inner = 0; inner < DT_NUM; ++inner) |
| 1828 | if (dependencies[cnt][inner] && ! has_dt[inner]) |
| 1829 | { |
| 1830 | char buf1[50]; |
| 1831 | char buf2[50]; |
| 1832 | |
| 1833 | ERROR (gettext ("\ |
| 1834 | section [%2d] '%s': contains %s entry but not %s\n"), |
| 1835 | idx, section_name (ebl, idx), |
| 1836 | ebl_dynamic_tag_name (ebl, cnt, buf1, sizeof (buf1)), |
| 1837 | ebl_dynamic_tag_name (ebl, inner, buf2, sizeof (buf2))); |
| 1838 | } |
| 1839 | } |
| 1840 | else |
| 1841 | { |
| 1842 | if (mandatory[cnt]) |
| 1843 | { |
| 1844 | char buf[50]; |
| 1845 | ERROR (gettext ("\ |
| 1846 | section [%2d] '%s': mandatory tag %s not present\n"), |
| 1847 | idx, section_name (ebl, idx), |
| 1848 | ebl_dynamic_tag_name (ebl, cnt, buf, sizeof (buf))); |
| 1849 | } |
| 1850 | } |
| 1851 | |
| 1852 | /* Make sure we have an hash table. */ |
| 1853 | if (!has_dt[DT_HASH] && !has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)]) |
| 1854 | ERROR (gettext ("\ |
| 1855 | section [%2d] '%s': no hash section present\n"), |
| 1856 | idx, section_name (ebl, idx)); |
| 1857 | |
| 1858 | /* The GNU-style hash table also needs a symbol table. */ |
| 1859 | if (!has_dt[DT_HASH] && has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)] |
| 1860 | && !has_dt[DT_SYMTAB]) |
| 1861 | ERROR (gettext ("\ |
| 1862 | section [%2d] '%s': contains %s entry but not %s\n"), |
| 1863 | idx, section_name (ebl, idx), |
| 1864 | "DT_GNU_HASH", "DT_SYMTAB"); |
| 1865 | |
| 1866 | /* Check the rel/rela tags. At least one group must be available. */ |
| 1867 | if ((has_dt[DT_RELA] || has_dt[DT_RELASZ] || has_dt[DT_RELAENT]) |
| 1868 | && (!has_dt[DT_RELA] || !has_dt[DT_RELASZ] || !has_dt[DT_RELAENT])) |
| 1869 | ERROR (gettext ("\ |
| 1870 | section [%2d] '%s': not all of %s, %s, and %s are present\n"), |
| 1871 | idx, section_name (ebl, idx), |
| 1872 | "DT_RELA", "DT_RELASZ", "DT_RELAENT"); |
| 1873 | |
| 1874 | if ((has_dt[DT_REL] || has_dt[DT_RELSZ] || has_dt[DT_RELENT]) |
| 1875 | && (!has_dt[DT_REL] || !has_dt[DT_RELSZ] || !has_dt[DT_RELENT])) |
| 1876 | ERROR (gettext ("\ |
| 1877 | section [%2d] '%s': not all of %s, %s, and %s are present\n"), |
| 1878 | idx, section_name (ebl, idx), |
| 1879 | "DT_REL", "DT_RELSZ", "DT_RELENT"); |
| 1880 | |
| 1881 | /* Check that all prelink sections are present if any of them is. */ |
| 1882 | if (has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)] |
| 1883 | || has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)]) |
| 1884 | { |
| 1885 | if (!has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)]) |
| 1886 | ERROR (gettext ("\ |
| 1887 | section [%2d] '%s': %s tag missing in DSO marked during prelinking\n"), |
| 1888 | idx, section_name (ebl, idx), "DT_GNU_PRELINKED"); |
| 1889 | if (!has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)]) |
| 1890 | ERROR (gettext ("\ |
| 1891 | section [%2d] '%s': %s tag missing in DSO marked during prelinking\n"), |
| 1892 | idx, section_name (ebl, idx), "DT_CHECKSUM"); |
| 1893 | |
| 1894 | /* Only DSOs can be marked like this. */ |
| 1895 | if (ehdr->e_type != ET_DYN) |
| 1896 | ERROR (gettext ("\ |
| 1897 | section [%2d] '%s': non-DSO file marked as dependency during prelink\n"), |
| 1898 | idx, section_name (ebl, idx)); |
| 1899 | } |
| 1900 | |
| 1901 | if (has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)] |
| 1902 | || has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)] |
| 1903 | || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)] |
| 1904 | || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)]) |
| 1905 | { |
| 1906 | if (!has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)]) |
| 1907 | ERROR (gettext ("\ |
| 1908 | section [%2d] '%s': %s tag missing in prelinked executable\n"), |
| 1909 | idx, section_name (ebl, idx), "DT_GNU_CONFLICTSZ"); |
| 1910 | if (!has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)]) |
| 1911 | ERROR (gettext ("\ |
| 1912 | section [%2d] '%s': %s tag missing in prelinked executable\n"), |
| 1913 | idx, section_name (ebl, idx), "DT_GNU_LIBLISTSZ"); |
| 1914 | if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)]) |
| 1915 | ERROR (gettext ("\ |
| 1916 | section [%2d] '%s': %s tag missing in prelinked executable\n"), |
| 1917 | idx, section_name (ebl, idx), "DT_GNU_CONFLICT"); |
| 1918 | if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)]) |
| 1919 | ERROR (gettext ("\ |
| 1920 | section [%2d] '%s': %s tag missing in prelinked executable\n"), |
| 1921 | idx, section_name (ebl, idx), "DT_GNU_LIBLIST"); |
| 1922 | } |
| 1923 | } |
| 1924 | |
| 1925 | |
| 1926 | static void |
| 1927 | check_symtab_shndx (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 1928 | { |
| 1929 | if (ehdr->e_type != ET_REL) |
| 1930 | { |
| 1931 | ERROR (gettext ("\ |
| 1932 | section [%2d] '%s': only relocatable files can have extended section index\n"), |
| 1933 | idx, section_name (ebl, idx)); |
| 1934 | return; |
| 1935 | } |
| 1936 | |
| 1937 | Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); |
| 1938 | GElf_Shdr symshdr_mem; |
| 1939 | GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); |
| 1940 | if (symshdr != NULL && symshdr->sh_type != SHT_SYMTAB) |
| 1941 | ERROR (gettext ("\ |
| 1942 | section [%2d] '%s': extended section index section not for symbol table\n"), |
| 1943 | idx, section_name (ebl, idx)); |
| 1944 | else if (symshdr == NULL) |
| 1945 | ERROR (gettext ("\ |
| 1946 | section [%2d] '%s': sh_link extended section index [%2d] is invalid\n"), |
| 1947 | idx, section_name (ebl, idx), shdr->sh_link); |
| 1948 | Elf_Data *symdata = elf_getdata (symscn, NULL); |
| 1949 | if (symdata == NULL) |
| 1950 | ERROR (gettext ("cannot get data for symbol section\n")); |
| 1951 | |
| 1952 | if (shdr->sh_entsize != sizeof (Elf32_Word)) |
| 1953 | ERROR (gettext ("\ |
| 1954 | section [%2d] '%s': entry size does not match Elf32_Word\n"), |
| 1955 | idx, section_name (ebl, idx)); |
| 1956 | |
| 1957 | if (symshdr != NULL |
| 1958 | && shdr->sh_entsize != 0 |
| 1959 | && symshdr->sh_entsize != 0 |
| 1960 | && (shdr->sh_size / shdr->sh_entsize |
| 1961 | < symshdr->sh_size / symshdr->sh_entsize)) |
| 1962 | ERROR (gettext ("\ |
| 1963 | section [%2d] '%s': extended index table too small for symbol table\n"), |
| 1964 | idx, section_name (ebl, idx)); |
| 1965 | |
| 1966 | if (shdr->sh_info != 0) |
| 1967 | ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"), |
| 1968 | idx, section_name (ebl, idx)); |
| 1969 | |
| 1970 | for (size_t cnt = idx + 1; cnt < shnum; ++cnt) |
| 1971 | { |
| 1972 | GElf_Shdr rshdr_mem; |
| 1973 | GElf_Shdr *rshdr = gelf_getshdr (elf_getscn (ebl->elf, cnt), &rshdr_mem); |
| 1974 | if (rshdr != NULL && rshdr->sh_type == SHT_SYMTAB_SHNDX |
| 1975 | && rshdr->sh_link == shdr->sh_link) |
| 1976 | { |
| 1977 | ERROR (gettext ("\ |
| 1978 | section [%2d] '%s': extended section index in section [%2zu] '%s' refers to same symbol table\n"), |
| 1979 | idx, section_name (ebl, idx), |
| 1980 | cnt, section_name (ebl, cnt)); |
| 1981 | break; |
| 1982 | } |
| 1983 | } |
| 1984 | |
| 1985 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 1986 | if (data == NULL || data->d_buf == NULL) |
| 1987 | { |
| 1988 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 1989 | idx, section_name (ebl, idx)); |
| 1990 | return; |
| 1991 | } |
| 1992 | |
| 1993 | if (data->d_size < sizeof (Elf32_Word) |
| 1994 | || *((Elf32_Word *) data->d_buf) != 0) |
| 1995 | ERROR (gettext ("symbol 0 should have zero extended section index\n")); |
| 1996 | |
| 1997 | for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt) |
| 1998 | { |
| 1999 | Elf32_Word xndx = ((Elf32_Word *) data->d_buf)[cnt]; |
| 2000 | |
| 2001 | if (xndx != 0) |
| 2002 | { |
| 2003 | GElf_Sym sym_data; |
| 2004 | GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_data); |
| 2005 | if (sym == NULL) |
| 2006 | { |
| 2007 | ERROR (gettext ("cannot get data for symbol %zu\n"), cnt); |
| 2008 | continue; |
| 2009 | } |
| 2010 | |
| 2011 | if (sym->st_shndx != SHN_XINDEX) |
| 2012 | ERROR (gettext ("\ |
| 2013 | extended section index is %" PRIu32 " but symbol index is not XINDEX\n"), |
| 2014 | (uint32_t) xndx); |
| 2015 | } |
| 2016 | } |
| 2017 | } |
| 2018 | |
| 2019 | |
| 2020 | static void |
| 2021 | check_sysv_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, |
| 2022 | GElf_Shdr *symshdr) |
| 2023 | { |
| 2024 | Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0]; |
| 2025 | Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1]; |
| 2026 | |
| 2027 | if (shdr->sh_size < (2 + nbucket + nchain) * sizeof (Elf32_Word)) |
| 2028 | { |
| 2029 | ERROR (gettext ("\ |
| 2030 | section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), |
| 2031 | idx, section_name (ebl, idx), (long int) shdr->sh_size, |
| 2032 | (long int) ((2 + nbucket + nchain) * sizeof (Elf32_Word))); |
| 2033 | return; |
| 2034 | } |
| 2035 | |
| 2036 | size_t maxidx = nchain; |
| 2037 | |
| 2038 | if (symshdr != NULL && symshdr->sh_entsize != 0) |
| 2039 | { |
| 2040 | size_t symsize = symshdr->sh_size / symshdr->sh_entsize; |
| 2041 | |
| 2042 | if (nchain > symshdr->sh_size / symshdr->sh_entsize) |
| 2043 | ERROR (gettext ("section [%2d] '%s': chain array too large\n"), |
| 2044 | idx, section_name (ebl, idx)); |
| 2045 | |
| 2046 | maxidx = symsize; |
| 2047 | } |
| 2048 | |
| 2049 | Elf32_Word *buf = (Elf32_Word *) data->d_buf; |
| 2050 | Elf32_Word *end = (Elf32_Word *) ((char *) data->d_buf + shdr->sh_size); |
| 2051 | size_t cnt; |
| 2052 | for (cnt = 2; cnt < 2 + nbucket; ++cnt) |
| 2053 | { |
| 2054 | if (buf + cnt >= end) |
| 2055 | break; |
| 2056 | else if (buf[cnt] >= maxidx) |
| 2057 | ERROR (gettext ("\ |
| 2058 | section [%2d] '%s': hash bucket reference %zu out of bounds\n"), |
| 2059 | idx, section_name (ebl, idx), cnt - 2); |
| 2060 | } |
| 2061 | |
| 2062 | for (; cnt < 2 + nbucket + nchain; ++cnt) |
| 2063 | { |
| 2064 | if (buf + cnt >= end) |
| 2065 | break; |
| 2066 | else if (buf[cnt] >= maxidx) |
| 2067 | ERROR (gettext ("\ |
| 2068 | section [%2d] '%s': hash chain reference %zu out of bounds\n"), |
| 2069 | idx, section_name (ebl, idx), cnt - 2 - nbucket); |
| 2070 | } |
| 2071 | } |
| 2072 | |
| 2073 | |
| 2074 | static void |
| 2075 | check_sysv_hash64 (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, |
| 2076 | GElf_Shdr *symshdr) |
| 2077 | { |
| 2078 | Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0]; |
| 2079 | Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1]; |
| 2080 | |
| 2081 | if (shdr->sh_size < (2 + nbucket + nchain) * sizeof (Elf64_Xword)) |
| 2082 | { |
| 2083 | ERROR (gettext ("\ |
| 2084 | section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), |
| 2085 | idx, section_name (ebl, idx), (long int) shdr->sh_size, |
| 2086 | (long int) ((2 + nbucket + nchain) * sizeof (Elf64_Xword))); |
| 2087 | return; |
| 2088 | } |
| 2089 | |
| 2090 | size_t maxidx = nchain; |
| 2091 | |
| 2092 | if (symshdr != NULL && symshdr->sh_entsize != 0) |
| 2093 | { |
| 2094 | size_t symsize = symshdr->sh_size / symshdr->sh_entsize; |
| 2095 | |
| 2096 | if (nchain > symshdr->sh_size / symshdr->sh_entsize) |
| 2097 | ERROR (gettext ("section [%2d] '%s': chain array too large\n"), |
| 2098 | idx, section_name (ebl, idx)); |
| 2099 | |
| 2100 | maxidx = symsize; |
| 2101 | } |
| 2102 | |
| 2103 | Elf64_Xword *buf = (Elf64_Xword *) data->d_buf; |
| 2104 | Elf64_Xword *end = (Elf64_Xword *) ((char *) data->d_buf + shdr->sh_size); |
| 2105 | size_t cnt; |
| 2106 | for (cnt = 2; cnt < 2 + nbucket; ++cnt) |
| 2107 | { |
| 2108 | if (buf + cnt >= end) |
| 2109 | break; |
| 2110 | else if (buf[cnt] >= maxidx) |
| 2111 | ERROR (gettext ("\ |
| 2112 | section [%2d] '%s': hash bucket reference %zu out of bounds\n"), |
| 2113 | idx, section_name (ebl, idx), cnt - 2); |
| 2114 | } |
| 2115 | |
| 2116 | for (; cnt < 2 + nbucket + nchain; ++cnt) |
| 2117 | { |
| 2118 | if (buf + cnt >= end) |
| 2119 | break; |
| 2120 | else if (buf[cnt] >= maxidx) |
| 2121 | ERROR (gettext ("\ |
| 2122 | section [%2d] '%s': hash chain reference %" PRIu64 " out of bounds\n"), |
| 2123 | idx, section_name (ebl, idx), (uint64_t) cnt - 2 - nbucket); |
| 2124 | } |
| 2125 | } |
| 2126 | |
| 2127 | |
| 2128 | static void |
| 2129 | check_gnu_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, |
| 2130 | GElf_Shdr *symshdr) |
| 2131 | { |
| 2132 | if (data->d_size < 4 * sizeof (Elf32_Word)) |
| 2133 | { |
| 2134 | ERROR (gettext ("\ |
| 2135 | section [%2d] '%s': not enough data\n"), |
| 2136 | idx, section_name (ebl, idx)); |
| 2137 | return; |
| 2138 | } |
| 2139 | |
| 2140 | Elf32_Word nbuckets = ((Elf32_Word *) data->d_buf)[0]; |
| 2141 | Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1]; |
| 2142 | Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2]; |
| 2143 | |
| 2144 | if (bitmask_words == 0 || !powerof2 (bitmask_words)) |
| 2145 | { |
| 2146 | ERROR (gettext ("\ |
| 2147 | section [%2d] '%s': bitmask size zero or not power of 2: %u\n"), |
| 2148 | idx, section_name (ebl, idx), bitmask_words); |
| 2149 | return; |
| 2150 | } |
| 2151 | |
| 2152 | size_t bitmask_idxmask = bitmask_words - 1; |
| 2153 | if (gelf_getclass (ebl->elf) == ELFCLASS64) |
| 2154 | bitmask_words *= 2; |
| 2155 | Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3]; |
| 2156 | |
| 2157 | /* Is there still room for the sym chain? |
| 2158 | Use uint64_t calculation to prevent 32bit overlow. */ |
| 2159 | uint64_t used_buf = (4ULL + bitmask_words + nbuckets) * sizeof (Elf32_Word); |
| 2160 | if (used_buf > data->d_size) |
| 2161 | { |
| 2162 | ERROR (gettext ("\ |
| 2163 | section [%2d] '%s': hash table section is too small (is %ld, expected at least %ld)\n"), |
| 2164 | idx, section_name (ebl, idx), (long int) shdr->sh_size, |
| 2165 | (long int) used_buf); |
| 2166 | return; |
| 2167 | } |
| 2168 | |
| 2169 | if (shift > 31) |
| 2170 | { |
| 2171 | ERROR (gettext ("\ |
| 2172 | section [%2d] '%s': 2nd hash function shift too big: %u\n"), |
| 2173 | idx, section_name (ebl, idx), shift); |
| 2174 | return; |
| 2175 | } |
| 2176 | |
| 2177 | size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (4 + bitmask_words |
| 2178 | + nbuckets); |
| 2179 | |
| 2180 | if (symshdr != NULL && symshdr->sh_entsize != 0) |
| 2181 | maxidx = MIN (maxidx, symshdr->sh_size / symshdr->sh_entsize); |
| 2182 | |
| 2183 | /* We need the symbol section data. */ |
| 2184 | Elf_Data *symdata = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), NULL); |
| 2185 | |
| 2186 | union |
| 2187 | { |
| 2188 | Elf32_Word *p32; |
| 2189 | Elf64_Xword *p64; |
| 2190 | } bitmask = { .p32 = &((Elf32_Word *) data->d_buf)[4] }, |
| 2191 | collected = { .p32 = xcalloc (bitmask_words, sizeof (Elf32_Word)) }; |
| 2192 | |
| 2193 | size_t classbits = gelf_getclass (ebl->elf) == ELFCLASS32 ? 32 : 64; |
| 2194 | |
| 2195 | size_t cnt; |
| 2196 | for (cnt = 4 + bitmask_words; cnt < 4 + bitmask_words + nbuckets; ++cnt) |
| 2197 | { |
| 2198 | Elf32_Word symidx = ((Elf32_Word *) data->d_buf)[cnt]; |
| 2199 | |
| 2200 | if (symidx == 0) |
| 2201 | continue; |
| 2202 | |
| 2203 | if (symidx < symbias) |
| 2204 | { |
| 2205 | ERROR (gettext ("\ |
| 2206 | section [%2d] '%s': hash chain for bucket %zu lower than symbol index bias\n"), |
| 2207 | idx, section_name (ebl, idx), cnt - (4 + bitmask_words)); |
| 2208 | continue; |
| 2209 | } |
| 2210 | |
| 2211 | while (symidx - symbias < maxidx) |
| 2212 | { |
| 2213 | Elf32_Word chainhash = ((Elf32_Word *) data->d_buf)[4 |
| 2214 | + bitmask_words |
| 2215 | + nbuckets |
| 2216 | + symidx |
| 2217 | - symbias]; |
| 2218 | |
| 2219 | if (symdata != NULL) |
| 2220 | { |
| 2221 | /* Check that the referenced symbol is not undefined. */ |
| 2222 | GElf_Sym sym_mem; |
| 2223 | GElf_Sym *sym = gelf_getsym (symdata, symidx, &sym_mem); |
| 2224 | if (sym != NULL && sym->st_shndx == SHN_UNDEF |
| 2225 | && GELF_ST_TYPE (sym->st_info) != STT_FUNC) |
| 2226 | ERROR (gettext ("\ |
| 2227 | section [%2d] '%s': symbol %u referenced in chain for bucket %zu is undefined\n"), |
| 2228 | idx, section_name (ebl, idx), symidx, |
| 2229 | cnt - (4 + bitmask_words)); |
| 2230 | |
| 2231 | const char *symname = (sym != NULL |
| 2232 | ? elf_strptr (ebl->elf, symshdr->sh_link, |
| 2233 | sym->st_name) |
| 2234 | : NULL); |
| 2235 | if (symname != NULL) |
| 2236 | { |
| 2237 | Elf32_Word hval = elf_gnu_hash (symname); |
| 2238 | if ((hval & ~1u) != (chainhash & ~1u)) |
| 2239 | ERROR (gettext ("\ |
| 2240 | section [%2d] '%s': hash value for symbol %u in chain for bucket %zu wrong\n"), |
| 2241 | idx, section_name (ebl, idx), symidx, |
| 2242 | cnt - (4 + bitmask_words)); |
| 2243 | |
| 2244 | /* Set the bits in the bitmask. */ |
| 2245 | size_t maskidx = (hval / classbits) & bitmask_idxmask; |
| 2246 | if (maskidx >= bitmask_words) |
| 2247 | { |
| 2248 | ERROR (gettext ("\ |
| 2249 | section [%2d] '%s': mask index for symbol %u in chain for bucket %zu wrong\n"), |
| 2250 | idx, section_name (ebl, idx), symidx, |
| 2251 | cnt - (4 + bitmask_words)); |
| 2252 | return; |
| 2253 | } |
| 2254 | if (classbits == 32) |
| 2255 | { |
| 2256 | collected.p32[maskidx] |
| 2257 | |= UINT32_C (1) << (hval & (classbits - 1)); |
| 2258 | collected.p32[maskidx] |
| 2259 | |= UINT32_C (1) << ((hval >> shift) & (classbits - 1)); |
| 2260 | } |
| 2261 | else |
| 2262 | { |
| 2263 | collected.p64[maskidx] |
| 2264 | |= UINT64_C (1) << (hval & (classbits - 1)); |
| 2265 | collected.p64[maskidx] |
| 2266 | |= UINT64_C (1) << ((hval >> shift) & (classbits - 1)); |
| 2267 | } |
| 2268 | } |
| 2269 | } |
| 2270 | |
| 2271 | if ((chainhash & 1) != 0) |
| 2272 | break; |
| 2273 | |
| 2274 | ++symidx; |
| 2275 | } |
| 2276 | |
| 2277 | if (symidx - symbias >= maxidx) |
| 2278 | ERROR (gettext ("\ |
| 2279 | section [%2d] '%s': hash chain for bucket %zu out of bounds\n"), |
| 2280 | idx, section_name (ebl, idx), cnt - (4 + bitmask_words)); |
| 2281 | else if (symshdr != NULL && symshdr->sh_entsize != 0 |
| 2282 | && symidx > symshdr->sh_size / symshdr->sh_entsize) |
| 2283 | ERROR (gettext ("\ |
| 2284 | section [%2d] '%s': symbol reference in chain for bucket %zu out of bounds\n"), |
| 2285 | idx, section_name (ebl, idx), cnt - (4 + bitmask_words)); |
| 2286 | } |
| 2287 | |
| 2288 | if (memcmp (collected.p32, bitmask.p32, bitmask_words * sizeof (Elf32_Word))) |
| 2289 | ERROR (gettext ("\ |
| 2290 | section [%2d] '%s': bitmask does not match names in the hash table\n"), |
| 2291 | idx, section_name (ebl, idx)); |
| 2292 | |
| 2293 | free (collected.p32); |
| 2294 | } |
| 2295 | |
| 2296 | |
| 2297 | static void |
| 2298 | check_hash (int tag, Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 2299 | { |
| 2300 | if (ehdr->e_type == ET_REL) |
| 2301 | { |
| 2302 | ERROR (gettext ("\ |
| 2303 | section [%2d] '%s': relocatable files cannot have hash tables\n"), |
| 2304 | idx, section_name (ebl, idx)); |
| 2305 | return; |
| 2306 | } |
| 2307 | |
| 2308 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 2309 | if (data == NULL || data->d_buf == NULL) |
| 2310 | { |
| 2311 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 2312 | idx, section_name (ebl, idx)); |
| 2313 | return; |
| 2314 | } |
| 2315 | |
| 2316 | GElf_Shdr symshdr_mem; |
| 2317 | GElf_Shdr *symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), |
| 2318 | &symshdr_mem); |
| 2319 | if (symshdr != NULL && symshdr->sh_type != SHT_DYNSYM) |
| 2320 | ERROR (gettext ("\ |
| 2321 | section [%2d] '%s': hash table not for dynamic symbol table\n"), |
| 2322 | idx, section_name (ebl, idx)); |
| 2323 | else if (symshdr == NULL) |
| 2324 | ERROR (gettext ("\ |
| 2325 | section [%2d] '%s': invalid sh_link symbol table section index [%2d]\n"), |
| 2326 | idx, section_name (ebl, idx), shdr->sh_link); |
| 2327 | |
| 2328 | size_t expect_entsize = (tag == SHT_GNU_HASH |
| 2329 | ? (gelf_getclass (ebl->elf) == ELFCLASS32 |
| 2330 | ? sizeof (Elf32_Word) : 0) |
| 2331 | : (size_t) ebl_sysvhash_entrysize (ebl)); |
| 2332 | |
| 2333 | if (shdr->sh_entsize != expect_entsize) |
| 2334 | ERROR (gettext ("\ |
| 2335 | section [%2d] '%s': hash table entry size incorrect\n"), |
| 2336 | idx, section_name (ebl, idx)); |
| 2337 | |
| 2338 | if ((shdr->sh_flags & SHF_ALLOC) == 0) |
| 2339 | ERROR (gettext ("section [%2d] '%s': not marked to be allocated\n"), |
| 2340 | idx, section_name (ebl, idx)); |
| 2341 | |
| 2342 | if (shdr->sh_size < (tag == SHT_GNU_HASH ? 4 : 2) * (expect_entsize ?: 4)) |
| 2343 | { |
| 2344 | ERROR (gettext ("\ |
| 2345 | section [%2d] '%s': hash table has not even room for initial administrative entries\n"), |
| 2346 | idx, section_name (ebl, idx)); |
| 2347 | return; |
| 2348 | } |
| 2349 | |
| 2350 | switch (tag) |
| 2351 | { |
| 2352 | case SHT_HASH: |
| 2353 | if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword)) |
| 2354 | check_sysv_hash64 (ebl, shdr, data, idx, symshdr); |
| 2355 | else |
| 2356 | check_sysv_hash (ebl, shdr, data, idx, symshdr); |
| 2357 | break; |
| 2358 | |
| 2359 | case SHT_GNU_HASH: |
| 2360 | check_gnu_hash (ebl, shdr, data, idx, symshdr); |
| 2361 | break; |
| 2362 | |
| 2363 | default: |
| 2364 | assert (! "should not happen"); |
| 2365 | } |
| 2366 | } |
| 2367 | |
| 2368 | |
| 2369 | /* Compare content of both hash tables, it must be identical. */ |
| 2370 | static void |
| 2371 | compare_hash_gnu_hash (Ebl *ebl, GElf_Ehdr *ehdr, size_t hash_idx, |
| 2372 | size_t gnu_hash_idx) |
| 2373 | { |
| 2374 | Elf_Scn *hash_scn = elf_getscn (ebl->elf, hash_idx); |
| 2375 | Elf_Data *hash_data = elf_getdata (hash_scn, NULL); |
| 2376 | GElf_Shdr hash_shdr_mem; |
| 2377 | GElf_Shdr *hash_shdr = gelf_getshdr (hash_scn, &hash_shdr_mem); |
| 2378 | Elf_Scn *gnu_hash_scn = elf_getscn (ebl->elf, gnu_hash_idx); |
| 2379 | Elf_Data *gnu_hash_data = elf_getdata (gnu_hash_scn, NULL); |
| 2380 | GElf_Shdr gnu_hash_shdr_mem; |
| 2381 | GElf_Shdr *gnu_hash_shdr = gelf_getshdr (gnu_hash_scn, &gnu_hash_shdr_mem); |
| 2382 | |
| 2383 | if (hash_shdr == NULL || gnu_hash_shdr == NULL |
| 2384 | || hash_data == NULL || hash_data->d_buf == NULL |
| 2385 | || gnu_hash_data == NULL || gnu_hash_data->d_buf == NULL) |
| 2386 | /* None of these pointers should be NULL since we used the |
| 2387 | sections already. We are careful nonetheless. */ |
| 2388 | return; |
| 2389 | |
| 2390 | /* The link must point to the same symbol table. */ |
| 2391 | if (hash_shdr->sh_link != gnu_hash_shdr->sh_link) |
| 2392 | { |
| 2393 | ERROR (gettext ("\ |
| 2394 | sh_link in hash sections [%2zu] '%s' and [%2zu] '%s' not identical\n"), |
| 2395 | hash_idx, elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name), |
| 2396 | gnu_hash_idx, |
| 2397 | elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name)); |
| 2398 | return; |
| 2399 | } |
| 2400 | |
| 2401 | Elf_Scn *sym_scn = elf_getscn (ebl->elf, hash_shdr->sh_link); |
| 2402 | Elf_Data *sym_data = elf_getdata (sym_scn, NULL); |
| 2403 | GElf_Shdr sym_shdr_mem; |
| 2404 | GElf_Shdr *sym_shdr = gelf_getshdr (sym_scn, &sym_shdr_mem); |
| 2405 | |
| 2406 | if (sym_data == NULL || sym_data->d_buf == NULL |
| 2407 | || sym_shdr == NULL || sym_shdr->sh_entsize == 0) |
| 2408 | return; |
| 2409 | |
| 2410 | const char *hash_name; |
| 2411 | const char *gnu_hash_name; |
| 2412 | hash_name = elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name); |
| 2413 | gnu_hash_name = elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name); |
| 2414 | |
| 2415 | if (gnu_hash_data->d_size < 4 * sizeof (Elf32_Word)) |
| 2416 | { |
| 2417 | ERROR (gettext ("\ |
| 2418 | hash section [%2zu] '%s' does not contain enough data\n"), |
| 2419 | gnu_hash_idx, gnu_hash_name); |
| 2420 | return; |
| 2421 | } |
| 2422 | |
| 2423 | uint32_t nentries = sym_shdr->sh_size / sym_shdr->sh_entsize; |
| 2424 | char *used = alloca (nentries); |
| 2425 | memset (used, '\0', nentries); |
| 2426 | |
| 2427 | /* First go over the GNU_HASH table and mark the entries as used. */ |
| 2428 | const Elf32_Word *gnu_hasharr = (Elf32_Word *) gnu_hash_data->d_buf; |
| 2429 | Elf32_Word gnu_nbucket = gnu_hasharr[0]; |
| 2430 | Elf32_Word gnu_symbias = gnu_hasharr[1]; |
| 2431 | const int bitmap_factor = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 1 : 2; |
| 2432 | const Elf32_Word *gnu_bucket = (gnu_hasharr |
| 2433 | + (4 + gnu_hasharr[2] * bitmap_factor)); |
| 2434 | const Elf32_Word *gnu_chain = gnu_bucket + gnu_hasharr[0]; |
| 2435 | |
| 2436 | if (gnu_hasharr[2] == 0) |
| 2437 | { |
| 2438 | ERROR (gettext ("\ |
| 2439 | hash section [%2zu] '%s' has zero bit mask words\n"), |
| 2440 | gnu_hash_idx, gnu_hash_name); |
| 2441 | return; |
| 2442 | } |
| 2443 | |
| 2444 | uint64_t used_buf = ((4ULL + gnu_hasharr[2] * bitmap_factor + gnu_nbucket) |
| 2445 | * sizeof (Elf32_Word)); |
| 2446 | uint32_t max_nsyms = (gnu_hash_data->d_size - used_buf) / sizeof (Elf32_Word); |
| 2447 | if (used_buf > gnu_hash_data->d_size) |
| 2448 | { |
| 2449 | ERROR (gettext ("\ |
| 2450 | hash section [%2zu] '%s' uses too much data\n"), |
| 2451 | gnu_hash_idx, gnu_hash_name); |
| 2452 | return; |
| 2453 | } |
| 2454 | |
| 2455 | for (Elf32_Word cnt = 0; cnt < gnu_nbucket; ++cnt) |
| 2456 | { |
| 2457 | if (gnu_bucket[cnt] != STN_UNDEF) |
| 2458 | { |
| 2459 | Elf32_Word symidx = gnu_bucket[cnt] - gnu_symbias; |
| 2460 | do |
| 2461 | { |
| 2462 | if (symidx >= max_nsyms || symidx + gnu_symbias >= nentries) |
| 2463 | { |
| 2464 | ERROR (gettext ("\ |
| 2465 | hash section [%2zu] '%s' invalid symbol index %" PRIu32 " (max_nsyms: %" PRIu32 ", nentries: %" PRIu32 "\n"), |
| 2466 | gnu_hash_idx, gnu_hash_name, symidx, max_nsyms, nentries); |
| 2467 | return; |
| 2468 | } |
| 2469 | used[symidx + gnu_symbias] |= 1; |
| 2470 | } |
| 2471 | while ((gnu_chain[symidx++] & 1u) == 0); |
| 2472 | } |
| 2473 | } |
| 2474 | |
| 2475 | /* Now go over the old hash table and check that we cover the same |
| 2476 | entries. */ |
| 2477 | if (hash_shdr->sh_entsize == sizeof (Elf32_Word)) |
| 2478 | { |
| 2479 | const Elf32_Word *hasharr = (Elf32_Word *) hash_data->d_buf; |
| 2480 | if (hash_data->d_size < 2 * sizeof (Elf32_Word)) |
| 2481 | { |
| 2482 | ERROR (gettext ("\ |
| 2483 | hash section [%2zu] '%s' does not contain enough data\n"), |
| 2484 | hash_idx, hash_name); |
| 2485 | return; |
| 2486 | } |
| 2487 | |
| 2488 | Elf32_Word nbucket = hasharr[0]; |
| 2489 | Elf32_Word nchain = hasharr[1]; |
| 2490 | uint64_t hash_used = (2ULL + nchain + nbucket) * sizeof (Elf32_Word); |
| 2491 | if (hash_used > hash_data->d_size) |
| 2492 | { |
| 2493 | ERROR (gettext ("\ |
| 2494 | hash section [%2zu] '%s' uses too much data\n"), |
| 2495 | hash_idx, hash_name); |
| 2496 | return; |
| 2497 | } |
| 2498 | |
| 2499 | const Elf32_Word *bucket = &hasharr[2]; |
| 2500 | const Elf32_Word *chain = &hasharr[2 + nbucket]; |
| 2501 | |
| 2502 | for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt) |
| 2503 | { |
| 2504 | Elf32_Word symidx = bucket[cnt]; |
| 2505 | while (symidx != STN_UNDEF && symidx < nentries && symidx < nchain) |
| 2506 | { |
| 2507 | used[symidx] |= 2; |
| 2508 | symidx = chain[symidx]; |
| 2509 | } |
| 2510 | } |
| 2511 | } |
| 2512 | else if (hash_shdr->sh_entsize == sizeof (Elf64_Xword)) |
| 2513 | { |
| 2514 | const Elf64_Xword *hasharr = (Elf64_Xword *) hash_data->d_buf; |
| 2515 | if (hash_data->d_size < 2 * sizeof (Elf32_Word)) |
| 2516 | { |
| 2517 | ERROR (gettext ("\ |
| 2518 | hash section [%2zu] '%s' does not contain enough data\n"), |
| 2519 | hash_idx, hash_name); |
| 2520 | return; |
| 2521 | } |
| 2522 | |
| 2523 | Elf64_Xword nbucket = hasharr[0]; |
| 2524 | Elf64_Xword nchain = hasharr[1]; |
| 2525 | uint64_t maxwords = hash_data->d_size / sizeof (Elf64_Xword); |
| 2526 | if (maxwords < 2 |
| 2527 | || maxwords - 2 < nbucket |
| 2528 | || maxwords - 2 - nbucket < nchain) |
| 2529 | { |
| 2530 | ERROR (gettext ("\ |
| 2531 | hash section [%2zu] '%s' uses too much data\n"), |
| 2532 | hash_idx, hash_name); |
| 2533 | return; |
| 2534 | } |
| 2535 | |
| 2536 | const Elf64_Xword *bucket = &hasharr[2]; |
| 2537 | const Elf64_Xword *chain = &hasharr[2 + nbucket]; |
| 2538 | |
| 2539 | for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt) |
| 2540 | { |
| 2541 | Elf64_Xword symidx = bucket[cnt]; |
| 2542 | while (symidx != STN_UNDEF && symidx < nentries && symidx < nchain) |
| 2543 | { |
| 2544 | used[symidx] |= 2; |
| 2545 | symidx = chain[symidx]; |
| 2546 | } |
| 2547 | } |
| 2548 | } |
| 2549 | else |
| 2550 | { |
| 2551 | ERROR (gettext ("\ |
| 2552 | hash section [%2zu] '%s' invalid sh_entsize\n"), |
| 2553 | hash_idx, hash_name); |
| 2554 | return; |
| 2555 | } |
| 2556 | |
| 2557 | /* Now see which entries are not set in one or both hash tables |
| 2558 | (unless the symbol is undefined in which case it can be omitted |
| 2559 | in the new table format). */ |
| 2560 | if ((used[0] & 1) != 0) |
| 2561 | ERROR (gettext ("section [%2zu] '%s': reference to symbol index 0\n"), |
| 2562 | gnu_hash_idx, |
| 2563 | elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name)); |
| 2564 | if ((used[0] & 2) != 0) |
| 2565 | ERROR (gettext ("section [%2zu] '%s': reference to symbol index 0\n"), |
| 2566 | hash_idx, elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name)); |
| 2567 | |
| 2568 | for (uint32_t cnt = 1; cnt < nentries; ++cnt) |
| 2569 | if (used[cnt] != 0 && used[cnt] != 3) |
| 2570 | { |
| 2571 | if (used[cnt] == 1) |
| 2572 | ERROR (gettext ("\ |
| 2573 | symbol %d referenced in new hash table in [%2zu] '%s' but not in old hash table in [%2zu] '%s'\n"), |
| 2574 | cnt, gnu_hash_idx, |
| 2575 | elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name), |
| 2576 | hash_idx, |
| 2577 | elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name)); |
| 2578 | else |
| 2579 | { |
| 2580 | GElf_Sym sym_mem; |
| 2581 | GElf_Sym *sym = gelf_getsym (sym_data, cnt, &sym_mem); |
| 2582 | |
| 2583 | if (sym != NULL && sym->st_shndx != STN_UNDEF) |
| 2584 | ERROR (gettext ("\ |
| 2585 | symbol %d referenced in old hash table in [%2zu] '%s' but not in new hash table in [%2zu] '%s'\n"), |
| 2586 | cnt, hash_idx, |
| 2587 | elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name), |
| 2588 | gnu_hash_idx, |
| 2589 | elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name)); |
| 2590 | } |
| 2591 | } |
| 2592 | } |
| 2593 | |
| 2594 | |
| 2595 | static void |
| 2596 | check_null (Ebl *ebl, GElf_Shdr *shdr, int idx) |
| 2597 | { |
| 2598 | #define TEST(name, extra) \ |
| 2599 | if (extra && shdr->sh_##name != 0) \ |
| 2600 | ERROR (gettext ("section [%2d] '%s': nonzero sh_%s for NULL section\n"), \ |
| 2601 | idx, section_name (ebl, idx), #name) |
| 2602 | |
| 2603 | TEST (name, 1); |
| 2604 | TEST (flags, 1); |
| 2605 | TEST (addr, 1); |
| 2606 | TEST (offset, 1); |
| 2607 | TEST (size, idx != 0); |
| 2608 | TEST (link, idx != 0); |
| 2609 | TEST (info, 1); |
| 2610 | TEST (addralign, 1); |
| 2611 | TEST (entsize, 1); |
| 2612 | } |
| 2613 | |
| 2614 | |
| 2615 | static void |
| 2616 | check_group (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 2617 | { |
| 2618 | if (ehdr->e_type != ET_REL) |
| 2619 | { |
| 2620 | ERROR (gettext ("\ |
| 2621 | section [%2d] '%s': section groups only allowed in relocatable object files\n"), |
| 2622 | idx, section_name (ebl, idx)); |
| 2623 | return; |
| 2624 | } |
| 2625 | |
| 2626 | /* Check that sh_link is an index of a symbol table. */ |
| 2627 | Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); |
| 2628 | GElf_Shdr symshdr_mem; |
| 2629 | GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); |
| 2630 | if (symshdr == NULL) |
| 2631 | ERROR (gettext ("section [%2d] '%s': cannot get symbol table: %s\n"), |
| 2632 | idx, section_name (ebl, idx), elf_errmsg (-1)); |
| 2633 | else |
| 2634 | { |
| 2635 | if (symshdr->sh_type != SHT_SYMTAB) |
| 2636 | ERROR (gettext ("\ |
| 2637 | section [%2d] '%s': section reference in sh_link is no symbol table\n"), |
| 2638 | idx, section_name (ebl, idx)); |
| 2639 | |
| 2640 | if (shdr->sh_info >= symshdr->sh_size / gelf_fsize (ebl->elf, ELF_T_SYM, |
| 2641 | 1, EV_CURRENT)) |
| 2642 | ERROR (gettext ("\ |
| 2643 | section [%2d] '%s': invalid symbol index in sh_info\n"), |
| 2644 | idx, section_name (ebl, idx)); |
| 2645 | |
| 2646 | if (shdr->sh_flags != 0) |
| 2647 | ERROR (gettext ("section [%2d] '%s': sh_flags not zero\n"), |
| 2648 | idx, section_name (ebl, idx)); |
| 2649 | |
| 2650 | GElf_Sym sym_data; |
| 2651 | GElf_Sym *sym = gelf_getsym (elf_getdata (symscn, NULL), shdr->sh_info, |
| 2652 | &sym_data); |
| 2653 | if (sym == NULL) |
| 2654 | ERROR (gettext ("\ |
| 2655 | section [%2d] '%s': cannot get symbol for signature\n"), |
| 2656 | idx, section_name (ebl, idx)); |
| 2657 | else if (elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name) == NULL) |
| 2658 | ERROR (gettext ("\ |
| 2659 | section [%2d] '%s': cannot get symbol name for signature\n"), |
| 2660 | idx, section_name (ebl, idx)); |
| 2661 | else if (strcmp (elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name), |
| 2662 | "") == 0) |
| 2663 | ERROR (gettext ("\ |
| 2664 | section [%2d] '%s': signature symbol cannot be empty string\n"), |
| 2665 | idx, section_name (ebl, idx)); |
| 2666 | |
| 2667 | if (be_strict |
| 2668 | && shdr->sh_entsize != elf32_fsize (ELF_T_WORD, 1, EV_CURRENT)) |
| 2669 | ERROR (gettext ("section [%2d] '%s': sh_flags not set correctly\n"), |
| 2670 | idx, section_name (ebl, idx)); |
| 2671 | } |
| 2672 | |
| 2673 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 2674 | if (data == NULL || data->d_buf == NULL) |
| 2675 | ERROR (gettext ("section [%2d] '%s': cannot get data: %s\n"), |
| 2676 | idx, section_name (ebl, idx), elf_errmsg (-1)); |
| 2677 | else |
| 2678 | { |
| 2679 | size_t elsize = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT); |
| 2680 | size_t cnt; |
| 2681 | Elf32_Word val; |
| 2682 | |
| 2683 | if (data->d_size % elsize != 0) |
| 2684 | ERROR (gettext ("\ |
| 2685 | section [%2d] '%s': section size not multiple of sizeof(Elf32_Word)\n"), |
| 2686 | idx, section_name (ebl, idx)); |
| 2687 | |
| 2688 | if (data->d_size < elsize) |
| 2689 | { |
| 2690 | ERROR (gettext ("\ |
| 2691 | section [%2d] '%s': section group without flags word\n"), |
| 2692 | idx, section_name (ebl, idx)); |
| 2693 | return; |
| 2694 | } |
| 2695 | else if (be_strict) |
| 2696 | { |
| 2697 | if (data->d_size < 2 * elsize) |
| 2698 | ERROR (gettext ("\ |
| 2699 | section [%2d] '%s': section group without member\n"), |
| 2700 | idx, section_name (ebl, idx)); |
| 2701 | else if (data->d_size < 3 * elsize) |
| 2702 | ERROR (gettext ("\ |
| 2703 | section [%2d] '%s': section group with only one member\n"), |
| 2704 | idx, section_name (ebl, idx)); |
| 2705 | } |
| 2706 | |
| 2707 | #if ALLOW_UNALIGNED |
| 2708 | val = *((Elf32_Word *) data->d_buf); |
| 2709 | #else |
| 2710 | memcpy (&val, data->d_buf, elsize); |
| 2711 | #endif |
| 2712 | if ((val & ~GRP_COMDAT) != 0) |
| 2713 | ERROR (gettext ("section [%2d] '%s': unknown section group flags\n"), |
| 2714 | idx, section_name (ebl, idx)); |
| 2715 | |
| 2716 | for (cnt = elsize; cnt < data->d_size; cnt += elsize) |
| 2717 | { |
| 2718 | #if ALLOW_UNALIGNED |
| 2719 | val = *((Elf32_Word *) ((char *) data->d_buf + cnt)); |
| 2720 | #else |
| 2721 | memcpy (&val, (char *) data->d_buf + cnt, elsize); |
| 2722 | #endif |
| 2723 | |
| 2724 | if (val > shnum) |
| 2725 | ERROR (gettext ("\ |
| 2726 | section [%2d] '%s': section index %zu out of range\n"), |
| 2727 | idx, section_name (ebl, idx), cnt / elsize); |
| 2728 | else |
| 2729 | { |
| 2730 | GElf_Shdr refshdr_mem; |
| 2731 | GElf_Shdr *refshdr = gelf_getshdr (elf_getscn (ebl->elf, val), |
| 2732 | &refshdr_mem); |
| 2733 | if (refshdr == NULL) |
| 2734 | ERROR (gettext ("\ |
| 2735 | section [%2d] '%s': cannot get section header for element %zu: %s\n"), |
| 2736 | idx, section_name (ebl, idx), cnt / elsize, |
| 2737 | elf_errmsg (-1)); |
| 2738 | else |
| 2739 | { |
| 2740 | if (refshdr->sh_type == SHT_GROUP) |
| 2741 | ERROR (gettext ("\ |
| 2742 | section [%2d] '%s': section group contains another group [%2d] '%s'\n"), |
| 2743 | idx, section_name (ebl, idx), |
| 2744 | val, section_name (ebl, val)); |
| 2745 | |
| 2746 | if ((refshdr->sh_flags & SHF_GROUP) == 0) |
| 2747 | ERROR (gettext ("\ |
| 2748 | section [%2d] '%s': element %zu references section [%2d] '%s' without SHF_GROUP flag set\n"), |
| 2749 | idx, section_name (ebl, idx), cnt / elsize, |
| 2750 | val, section_name (ebl, val)); |
| 2751 | } |
| 2752 | |
| 2753 | if (val < shnum && ++scnref[val] == 2) |
| 2754 | ERROR (gettext ("\ |
| 2755 | section [%2d] '%s' is contained in more than one section group\n"), |
| 2756 | val, section_name (ebl, val)); |
| 2757 | } |
| 2758 | } |
| 2759 | } |
| 2760 | } |
| 2761 | |
| 2762 | |
| 2763 | static const char * |
| 2764 | section_flags_string (GElf_Word flags, char *buf, size_t len) |
| 2765 | { |
| 2766 | if (flags == 0) |
| 2767 | return "none"; |
| 2768 | |
| 2769 | static const struct |
| 2770 | { |
| 2771 | GElf_Word flag; |
| 2772 | const char *name; |
| 2773 | } known_flags[] = |
| 2774 | { |
| 2775 | #define NEWFLAG(name) { SHF_##name, #name } |
| 2776 | NEWFLAG (WRITE), |
| 2777 | NEWFLAG (ALLOC), |
| 2778 | NEWFLAG (EXECINSTR), |
| 2779 | NEWFLAG (MERGE), |
| 2780 | NEWFLAG (STRINGS), |
| 2781 | NEWFLAG (INFO_LINK), |
| 2782 | NEWFLAG (LINK_ORDER), |
| 2783 | NEWFLAG (OS_NONCONFORMING), |
| 2784 | NEWFLAG (GROUP), |
| 2785 | NEWFLAG (TLS), |
| 2786 | NEWFLAG (COMPRESSED) |
| 2787 | }; |
| 2788 | #undef NEWFLAG |
| 2789 | const size_t nknown_flags = sizeof (known_flags) / sizeof (known_flags[0]); |
| 2790 | |
| 2791 | char *cp = buf; |
| 2792 | |
| 2793 | for (size_t cnt = 0; cnt < nknown_flags; ++cnt) |
| 2794 | if (flags & known_flags[cnt].flag) |
| 2795 | { |
| 2796 | if (cp != buf && len > 1) |
| 2797 | { |
| 2798 | *cp++ = '|'; |
| 2799 | --len; |
| 2800 | } |
| 2801 | |
| 2802 | size_t ncopy = MIN (len - 1, strlen (known_flags[cnt].name)); |
| 2803 | cp = mempcpy (cp, known_flags[cnt].name, ncopy); |
| 2804 | len -= ncopy; |
| 2805 | |
| 2806 | flags ^= known_flags[cnt].flag; |
| 2807 | } |
| 2808 | |
| 2809 | if (flags != 0 || cp == buf) |
| 2810 | snprintf (cp, len - 1, "%" PRIx64, (uint64_t) flags); |
| 2811 | |
| 2812 | *cp = '\0'; |
| 2813 | |
| 2814 | return buf; |
| 2815 | } |
| 2816 | |
| 2817 | |
| 2818 | static int |
| 2819 | has_copy_reloc (Ebl *ebl, unsigned int symscnndx, unsigned int symndx) |
| 2820 | { |
| 2821 | /* First find the relocation section for the symbol table. */ |
| 2822 | Elf_Scn *scn = NULL; |
| 2823 | GElf_Shdr shdr_mem; |
| 2824 | GElf_Shdr *shdr = NULL; |
| 2825 | while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) |
| 2826 | { |
| 2827 | shdr = gelf_getshdr (scn, &shdr_mem); |
| 2828 | if (shdr != NULL |
| 2829 | && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) |
| 2830 | && shdr->sh_link == symscnndx) |
| 2831 | /* Found the section. */ |
| 2832 | break; |
| 2833 | } |
| 2834 | |
| 2835 | if (scn == NULL) |
| 2836 | return 0; |
| 2837 | |
| 2838 | Elf_Data *data = elf_getdata (scn, NULL); |
| 2839 | if (data == NULL || shdr->sh_entsize == 0) |
| 2840 | return 0; |
| 2841 | |
| 2842 | if (shdr->sh_type == SHT_REL) |
| 2843 | for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize; ++i) |
| 2844 | { |
| 2845 | GElf_Rel rel_mem; |
| 2846 | GElf_Rel *rel = gelf_getrel (data, i, &rel_mem); |
| 2847 | if (rel == NULL) |
| 2848 | continue; |
| 2849 | |
| 2850 | if (GELF_R_SYM (rel->r_info) == symndx |
| 2851 | && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info))) |
| 2852 | return 1; |
| 2853 | } |
| 2854 | else |
| 2855 | for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize; ++i) |
| 2856 | { |
| 2857 | GElf_Rela rela_mem; |
| 2858 | GElf_Rela *rela = gelf_getrela (data, i, &rela_mem); |
| 2859 | if (rela == NULL) |
| 2860 | continue; |
| 2861 | |
| 2862 | if (GELF_R_SYM (rela->r_info) == symndx |
| 2863 | && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info))) |
| 2864 | return 1; |
| 2865 | } |
| 2866 | |
| 2867 | return 0; |
| 2868 | } |
| 2869 | |
| 2870 | |
| 2871 | static int |
| 2872 | in_nobits_scn (Ebl *ebl, unsigned int shndx) |
| 2873 | { |
| 2874 | GElf_Shdr shdr_mem; |
| 2875 | GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, shndx), &shdr_mem); |
| 2876 | return shdr != NULL && shdr->sh_type == SHT_NOBITS; |
| 2877 | } |
| 2878 | |
| 2879 | |
| 2880 | static struct version_namelist |
| 2881 | { |
| 2882 | const char *objname; |
| 2883 | const char *name; |
| 2884 | GElf_Versym ndx; |
| 2885 | enum { ver_def, ver_need } type; |
| 2886 | struct version_namelist *next; |
| 2887 | } *version_namelist; |
| 2888 | |
| 2889 | |
| 2890 | static int |
| 2891 | add_version (const char *objname, const char *name, GElf_Versym ndx, int type) |
| 2892 | { |
| 2893 | /* Check that there are no duplications. */ |
| 2894 | struct version_namelist *nlp = version_namelist; |
| 2895 | while (nlp != NULL) |
| 2896 | { |
| 2897 | if (((nlp->objname == NULL && objname == NULL) |
| 2898 | || (nlp->objname != NULL && objname != NULL |
| 2899 | && strcmp (nlp->objname, objname) == 0)) |
| 2900 | && strcmp (nlp->name, name) == 0) |
| 2901 | return nlp->type == ver_def ? 1 : -1; |
| 2902 | nlp = nlp->next; |
| 2903 | } |
| 2904 | |
| 2905 | nlp = xmalloc (sizeof (*nlp)); |
| 2906 | nlp->objname = objname; |
| 2907 | nlp->name = name; |
| 2908 | nlp->ndx = ndx; |
| 2909 | nlp->type = type; |
| 2910 | nlp->next = version_namelist; |
| 2911 | version_namelist = nlp; |
| 2912 | |
| 2913 | return 0; |
| 2914 | } |
| 2915 | |
| 2916 | |
| 2917 | static void |
| 2918 | check_versym (Ebl *ebl, int idx) |
| 2919 | { |
| 2920 | Elf_Scn *scn = elf_getscn (ebl->elf, idx); |
| 2921 | GElf_Shdr shdr_mem; |
| 2922 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); |
| 2923 | if (shdr == NULL) |
| 2924 | /* The error has already been reported. */ |
| 2925 | return; |
| 2926 | |
| 2927 | Elf_Data *data = elf_getdata (scn, NULL); |
| 2928 | if (data == NULL) |
| 2929 | { |
| 2930 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 2931 | idx, section_name (ebl, idx)); |
| 2932 | return; |
| 2933 | } |
| 2934 | |
| 2935 | Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link); |
| 2936 | GElf_Shdr symshdr_mem; |
| 2937 | GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem); |
| 2938 | if (symshdr == NULL) |
| 2939 | /* The error has already been reported. */ |
| 2940 | return; |
| 2941 | |
| 2942 | if (symshdr->sh_type != SHT_DYNSYM) |
| 2943 | { |
| 2944 | ERROR (gettext ("\ |
| 2945 | section [%2d] '%s' refers in sh_link to section [%2d] '%s' which is no dynamic symbol table\n"), |
| 2946 | idx, section_name (ebl, idx), |
| 2947 | shdr->sh_link, section_name (ebl, shdr->sh_link)); |
| 2948 | return; |
| 2949 | } |
| 2950 | |
| 2951 | /* The number of elements in the version symbol table must be the |
| 2952 | same as the number of symbols. */ |
| 2953 | if (shdr->sh_entsize != 0 && symshdr->sh_entsize != 0 |
| 2954 | && (shdr->sh_size / shdr->sh_entsize |
| 2955 | != symshdr->sh_size / symshdr->sh_entsize)) |
| 2956 | ERROR (gettext ("\ |
| 2957 | section [%2d] '%s' has different number of entries than symbol table [%2d] '%s'\n"), |
| 2958 | idx, section_name (ebl, idx), |
| 2959 | shdr->sh_link, section_name (ebl, shdr->sh_link)); |
| 2960 | |
| 2961 | Elf_Data *symdata = elf_getdata (symscn, NULL); |
| 2962 | if (symdata == NULL || shdr->sh_entsize == 0) |
| 2963 | /* The error has already been reported. */ |
| 2964 | return; |
| 2965 | |
| 2966 | for (int cnt = 1; (size_t) cnt < shdr->sh_size / shdr->sh_entsize; ++cnt) |
| 2967 | { |
| 2968 | GElf_Versym versym_mem; |
| 2969 | GElf_Versym *versym = gelf_getversym (data, cnt, &versym_mem); |
| 2970 | if (versym == NULL) |
| 2971 | { |
| 2972 | ERROR (gettext ("\ |
| 2973 | section [%2d] '%s': symbol %d: cannot read version data\n"), |
| 2974 | idx, section_name (ebl, idx), cnt); |
| 2975 | break; |
| 2976 | } |
| 2977 | |
| 2978 | GElf_Sym sym_mem; |
| 2979 | GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_mem); |
| 2980 | if (sym == NULL) |
| 2981 | /* Already reported elsewhere. */ |
| 2982 | continue; |
| 2983 | |
| 2984 | if (*versym == VER_NDX_GLOBAL) |
| 2985 | { |
| 2986 | /* Global symbol. Make sure it is not defined as local. */ |
| 2987 | if (GELF_ST_BIND (sym->st_info) == STB_LOCAL) |
| 2988 | ERROR (gettext ("\ |
| 2989 | section [%2d] '%s': symbol %d: local symbol with global scope\n"), |
| 2990 | idx, section_name (ebl, idx), cnt); |
| 2991 | } |
| 2992 | else if (*versym != VER_NDX_LOCAL) |
| 2993 | { |
| 2994 | /* Versioned symbol. Make sure it is not defined as local. */ |
| 2995 | if (!gnuld && GELF_ST_BIND (sym->st_info) == STB_LOCAL) |
| 2996 | ERROR (gettext ("\ |
| 2997 | section [%2d] '%s': symbol %d: local symbol with version\n"), |
| 2998 | idx, section_name (ebl, idx), cnt); |
| 2999 | |
| 3000 | /* Look through the list of defined versions and locate the |
| 3001 | index we need for this symbol. */ |
| 3002 | struct version_namelist *runp = version_namelist; |
| 3003 | while (runp != NULL) |
| 3004 | if (runp->ndx == (*versym & (GElf_Versym) 0x7fff)) |
| 3005 | break; |
| 3006 | else |
| 3007 | runp = runp->next; |
| 3008 | |
| 3009 | if (runp == NULL) |
| 3010 | ERROR (gettext ("\ |
| 3011 | section [%2d] '%s': symbol %d: invalid version index %d\n"), |
| 3012 | idx, section_name (ebl, idx), cnt, (int) *versym); |
| 3013 | else if (sym->st_shndx == SHN_UNDEF |
| 3014 | && runp->type == ver_def) |
| 3015 | ERROR (gettext ("\ |
| 3016 | section [%2d] '%s': symbol %d: version index %d is for defined version\n"), |
| 3017 | idx, section_name (ebl, idx), cnt, (int) *versym); |
| 3018 | else if (sym->st_shndx != SHN_UNDEF |
| 3019 | && runp->type == ver_need) |
| 3020 | { |
| 3021 | /* Unless this symbol has a copy relocation associated |
| 3022 | this must not happen. */ |
| 3023 | if (!has_copy_reloc (ebl, shdr->sh_link, cnt) |
| 3024 | && !in_nobits_scn (ebl, sym->st_shndx)) |
| 3025 | ERROR (gettext ("\ |
| 3026 | section [%2d] '%s': symbol %d: version index %d is for requested version\n"), |
| 3027 | idx, section_name (ebl, idx), cnt, (int) *versym); |
| 3028 | } |
| 3029 | } |
| 3030 | } |
| 3031 | } |
| 3032 | |
| 3033 | |
| 3034 | static int |
| 3035 | unknown_dependency_p (Elf *elf, const char *fname) |
| 3036 | { |
| 3037 | GElf_Phdr phdr_mem; |
| 3038 | GElf_Phdr *phdr = NULL; |
| 3039 | |
| 3040 | unsigned int i; |
| 3041 | for (i = 0; i < phnum; ++i) |
| 3042 | if ((phdr = gelf_getphdr (elf, i, &phdr_mem)) != NULL |
| 3043 | && phdr->p_type == PT_DYNAMIC) |
| 3044 | break; |
| 3045 | |
| 3046 | if (i == phnum) |
| 3047 | return 1; |
| 3048 | assert (phdr != NULL); |
| 3049 | Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset); |
| 3050 | GElf_Shdr shdr_mem; |
| 3051 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); |
| 3052 | Elf_Data *data = elf_getdata (scn, NULL); |
| 3053 | if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC |
| 3054 | && data != NULL && shdr->sh_entsize != 0) |
| 3055 | for (size_t j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j) |
| 3056 | { |
| 3057 | GElf_Dyn dyn_mem; |
| 3058 | GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem); |
| 3059 | if (dyn != NULL && dyn->d_tag == DT_NEEDED) |
| 3060 | { |
| 3061 | const char *str = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val); |
| 3062 | if (str != NULL && strcmp (str, fname) == 0) |
| 3063 | /* Found it. */ |
| 3064 | return 0; |
| 3065 | } |
| 3066 | } |
| 3067 | |
| 3068 | return 1; |
| 3069 | } |
| 3070 | |
| 3071 | |
| 3072 | static unsigned int nverneed; |
| 3073 | |
| 3074 | static void |
| 3075 | check_verneed (Ebl *ebl, GElf_Shdr *shdr, int idx) |
| 3076 | { |
| 3077 | if (++nverneed == 2) |
| 3078 | ERROR (gettext ("more than one version reference section present\n")); |
| 3079 | |
| 3080 | GElf_Shdr strshdr_mem; |
| 3081 | GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), |
| 3082 | &strshdr_mem); |
| 3083 | if (strshdr == NULL) |
| 3084 | return; |
| 3085 | if (strshdr->sh_type != SHT_STRTAB) |
| 3086 | ERROR (gettext ("\ |
| 3087 | section [%2d] '%s': sh_link does not link to string table\n"), |
| 3088 | idx, section_name (ebl, idx)); |
| 3089 | |
| 3090 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 3091 | if (data == NULL) |
| 3092 | { |
| 3093 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 3094 | idx, section_name (ebl, idx)); |
| 3095 | return; |
| 3096 | } |
| 3097 | unsigned int offset = 0; |
| 3098 | for (Elf64_Word cnt = shdr->sh_info; cnt > 0; ) |
| 3099 | { |
| 3100 | cnt--; |
| 3101 | |
| 3102 | /* Get the data at the next offset. */ |
| 3103 | GElf_Verneed needmem; |
| 3104 | GElf_Verneed *need = gelf_getverneed (data, offset, &needmem); |
| 3105 | if (need == NULL) |
| 3106 | break; |
| 3107 | |
| 3108 | unsigned int auxoffset = offset + need->vn_aux; |
| 3109 | |
| 3110 | if (need->vn_version != EV_CURRENT) |
| 3111 | ERROR (gettext ("\ |
| 3112 | section [%2d] '%s': entry %d has wrong version %d\n"), |
| 3113 | idx, section_name (ebl, idx), cnt, (int) need->vn_version); |
| 3114 | |
| 3115 | if (need->vn_cnt > 0 && need->vn_aux < gelf_fsize (ebl->elf, ELF_T_VNEED, |
| 3116 | 1, EV_CURRENT)) |
| 3117 | { |
| 3118 | ERROR (gettext ("\ |
| 3119 | section [%2d] '%s': entry %d has wrong offset of auxiliary data\n"), |
| 3120 | idx, section_name (ebl, idx), cnt); |
| 3121 | break; |
| 3122 | } |
| 3123 | |
| 3124 | const char *libname = elf_strptr (ebl->elf, shdr->sh_link, |
| 3125 | need->vn_file); |
| 3126 | if (libname == NULL) |
| 3127 | { |
| 3128 | ERROR (gettext ("\ |
| 3129 | section [%2d] '%s': entry %d has invalid file reference\n"), |
| 3130 | idx, section_name (ebl, idx), cnt); |
| 3131 | goto next_need; |
| 3132 | } |
| 3133 | |
| 3134 | /* Check that there is a DT_NEEDED entry for the referenced library. */ |
| 3135 | if (unknown_dependency_p (ebl->elf, libname)) |
| 3136 | ERROR (gettext ("\ |
| 3137 | section [%2d] '%s': entry %d references unknown dependency\n"), |
| 3138 | idx, section_name (ebl, idx), cnt); |
| 3139 | |
| 3140 | for (int cnt2 = need->vn_cnt; --cnt2 >= 0; ) |
| 3141 | { |
| 3142 | GElf_Vernaux auxmem; |
| 3143 | GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem); |
| 3144 | if (aux == NULL) |
| 3145 | break; |
| 3146 | |
| 3147 | if ((aux->vna_flags & ~VER_FLG_WEAK) != 0) |
| 3148 | ERROR (gettext ("\ |
| 3149 | section [%2d] '%s': auxiliary entry %d of entry %d has unknown flag\n"), |
| 3150 | idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt); |
| 3151 | |
| 3152 | const char *verstr = elf_strptr (ebl->elf, shdr->sh_link, |
| 3153 | aux->vna_name); |
| 3154 | if (verstr == NULL) |
| 3155 | { |
| 3156 | ERROR (gettext ("\ |
| 3157 | section [%2d] '%s': auxiliary entry %d of entry %d has invalid name reference\n"), |
| 3158 | idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt); |
| 3159 | break; |
| 3160 | } |
| 3161 | else |
| 3162 | { |
| 3163 | GElf_Word hashval = elf_hash (verstr); |
| 3164 | if (hashval != aux->vna_hash) |
| 3165 | ERROR (gettext ("\ |
| 3166 | section [%2d] '%s': auxiliary entry %d of entry %d has wrong hash value: %#x, expected %#x\n"), |
| 3167 | idx, section_name (ebl, idx), need->vn_cnt - cnt2, |
| 3168 | cnt, (int) hashval, (int) aux->vna_hash); |
| 3169 | |
| 3170 | int res = add_version (libname, verstr, aux->vna_other, |
| 3171 | ver_need); |
| 3172 | if (unlikely (res !=0)) |
| 3173 | { |
| 3174 | ERROR (gettext ("\ |
| 3175 | section [%2d] '%s': auxiliary entry %d of entry %d has duplicate version name '%s'\n"), |
| 3176 | idx, section_name (ebl, idx), need->vn_cnt - cnt2, |
| 3177 | cnt, verstr); |
| 3178 | } |
| 3179 | } |
| 3180 | |
| 3181 | if ((aux->vna_next != 0 || cnt2 > 0) |
| 3182 | && aux->vna_next < gelf_fsize (ebl->elf, ELF_T_VNAUX, 1, |
| 3183 | EV_CURRENT)) |
| 3184 | { |
| 3185 | ERROR (gettext ("\ |
| 3186 | section [%2d] '%s': auxiliary entry %d of entry %d has wrong next field\n"), |
| 3187 | idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt); |
| 3188 | break; |
| 3189 | } |
| 3190 | |
| 3191 | auxoffset += MAX (aux->vna_next, |
| 3192 | gelf_fsize (ebl->elf, ELF_T_VNAUX, 1, EV_CURRENT)); |
| 3193 | } |
| 3194 | |
| 3195 | /* Find the next offset. */ |
| 3196 | next_need: |
| 3197 | offset += need->vn_next; |
| 3198 | |
| 3199 | if ((need->vn_next != 0 || cnt > 0) |
| 3200 | && offset < auxoffset) |
| 3201 | { |
| 3202 | ERROR (gettext ("\ |
| 3203 | section [%2d] '%s': entry %d has invalid offset to next entry\n"), |
| 3204 | idx, section_name (ebl, idx), cnt); |
| 3205 | break; |
| 3206 | } |
| 3207 | |
| 3208 | if (need->vn_next == 0 && cnt > 0) |
| 3209 | { |
| 3210 | ERROR (gettext ("\ |
| 3211 | section [%2d] '%s': entry %d has zero offset to next entry, but sh_info says there are more entries\n"), |
| 3212 | idx, section_name (ebl, idx), cnt); |
| 3213 | break; |
| 3214 | } |
| 3215 | } |
| 3216 | } |
| 3217 | |
| 3218 | |
| 3219 | static unsigned int nverdef; |
| 3220 | |
| 3221 | static void |
| 3222 | check_verdef (Ebl *ebl, GElf_Shdr *shdr, int idx) |
| 3223 | { |
| 3224 | if (++nverdef == 2) |
| 3225 | ERROR (gettext ("more than one version definition section present\n")); |
| 3226 | |
| 3227 | GElf_Shdr strshdr_mem; |
| 3228 | GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), |
| 3229 | &strshdr_mem); |
| 3230 | if (strshdr == NULL) |
| 3231 | return; |
| 3232 | if (strshdr->sh_type != SHT_STRTAB) |
| 3233 | ERROR (gettext ("\ |
| 3234 | section [%2d] '%s': sh_link does not link to string table\n"), |
| 3235 | idx, section_name (ebl, idx)); |
| 3236 | |
| 3237 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 3238 | if (data == NULL) |
| 3239 | { |
| 3240 | no_data: |
| 3241 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 3242 | idx, section_name (ebl, idx)); |
| 3243 | return; |
| 3244 | } |
| 3245 | |
| 3246 | /* Iterate over all version definition entries. We check that there |
| 3247 | is a BASE entry and that each index is unique. To do the later |
| 3248 | we collection the information in a list which is later |
| 3249 | examined. */ |
| 3250 | struct namelist |
| 3251 | { |
| 3252 | const char *name; |
| 3253 | struct namelist *next; |
| 3254 | } *namelist = NULL; |
| 3255 | struct namelist *refnamelist = NULL; |
| 3256 | |
| 3257 | bool has_base = false; |
| 3258 | unsigned int offset = 0; |
| 3259 | for (Elf64_Word cnt = shdr->sh_info; cnt > 0; ) |
| 3260 | { |
| 3261 | cnt--; |
| 3262 | |
| 3263 | /* Get the data at the next offset. */ |
| 3264 | GElf_Verdef defmem; |
| 3265 | GElf_Verdef *def = gelf_getverdef (data, offset, &defmem); |
| 3266 | if (def == NULL) |
| 3267 | goto no_data; |
| 3268 | |
| 3269 | if ((def->vd_flags & VER_FLG_BASE) != 0) |
| 3270 | { |
| 3271 | if (has_base) |
| 3272 | ERROR (gettext ("\ |
| 3273 | section [%2d] '%s': more than one BASE definition\n"), |
| 3274 | idx, section_name (ebl, idx)); |
| 3275 | if (def->vd_ndx != VER_NDX_GLOBAL) |
| 3276 | ERROR (gettext ("\ |
| 3277 | section [%2d] '%s': BASE definition must have index VER_NDX_GLOBAL\n"), |
| 3278 | idx, section_name (ebl, idx)); |
| 3279 | has_base = true; |
| 3280 | } |
| 3281 | if ((def->vd_flags & ~(VER_FLG_BASE|VER_FLG_WEAK)) != 0) |
| 3282 | ERROR (gettext ("\ |
| 3283 | section [%2d] '%s': entry %d has unknown flag\n"), |
| 3284 | idx, section_name (ebl, idx), cnt); |
| 3285 | |
| 3286 | if (def->vd_version != EV_CURRENT) |
| 3287 | ERROR (gettext ("\ |
| 3288 | section [%2d] '%s': entry %d has wrong version %d\n"), |
| 3289 | idx, section_name (ebl, idx), cnt, (int) def->vd_version); |
| 3290 | |
| 3291 | if (def->vd_cnt > 0 && def->vd_aux < gelf_fsize (ebl->elf, ELF_T_VDEF, |
| 3292 | 1, EV_CURRENT)) |
| 3293 | { |
| 3294 | ERROR (gettext ("\ |
| 3295 | section [%2d] '%s': entry %d has wrong offset of auxiliary data\n"), |
| 3296 | idx, section_name (ebl, idx), cnt); |
| 3297 | break; |
| 3298 | } |
| 3299 | |
| 3300 | unsigned int auxoffset = offset + def->vd_aux; |
| 3301 | GElf_Verdaux auxmem; |
| 3302 | GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem); |
| 3303 | if (aux == NULL) |
| 3304 | goto no_data; |
| 3305 | |
| 3306 | const char *name = elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name); |
| 3307 | if (name == NULL) |
| 3308 | { |
| 3309 | ERROR (gettext ("\ |
| 3310 | section [%2d] '%s': entry %d has invalid name reference\n"), |
| 3311 | idx, section_name (ebl, idx), cnt); |
| 3312 | goto next_def; |
| 3313 | } |
| 3314 | GElf_Word hashval = elf_hash (name); |
| 3315 | if (def->vd_hash != hashval) |
| 3316 | ERROR (gettext ("\ |
| 3317 | section [%2d] '%s': entry %d has wrong hash value: %#x, expected %#x\n"), |
| 3318 | idx, section_name (ebl, idx), cnt, (int) hashval, |
| 3319 | (int) def->vd_hash); |
| 3320 | |
| 3321 | int res = add_version (NULL, name, def->vd_ndx, ver_def); |
| 3322 | if (unlikely (res !=0)) |
| 3323 | { |
| 3324 | ERROR (gettext ("\ |
| 3325 | section [%2d] '%s': entry %d has duplicate version name '%s'\n"), |
| 3326 | idx, section_name (ebl, idx), cnt, name); |
| 3327 | } |
| 3328 | |
| 3329 | struct namelist *newname = alloca (sizeof (*newname)); |
| 3330 | newname->name = name; |
| 3331 | newname->next = namelist; |
| 3332 | namelist = newname; |
| 3333 | |
| 3334 | auxoffset += aux->vda_next; |
| 3335 | for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2) |
| 3336 | { |
| 3337 | aux = gelf_getverdaux (data, auxoffset, &auxmem); |
| 3338 | if (aux == NULL) |
| 3339 | goto no_data; |
| 3340 | |
| 3341 | name = elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name); |
| 3342 | if (name == NULL) |
| 3343 | { |
| 3344 | ERROR (gettext ("\ |
| 3345 | section [%2d] '%s': entry %d has invalid name reference in auxiliary data\n"), |
| 3346 | idx, section_name (ebl, idx), cnt); |
| 3347 | break; |
| 3348 | } |
| 3349 | else |
| 3350 | { |
| 3351 | newname = alloca (sizeof (*newname)); |
| 3352 | newname->name = name; |
| 3353 | newname->next = refnamelist; |
| 3354 | refnamelist = newname; |
| 3355 | } |
| 3356 | |
| 3357 | if ((aux->vda_next != 0 || cnt2 + 1 < def->vd_cnt) |
| 3358 | && aux->vda_next < gelf_fsize (ebl->elf, ELF_T_VDAUX, 1, |
| 3359 | EV_CURRENT)) |
| 3360 | { |
| 3361 | ERROR (gettext ("\ |
| 3362 | section [%2d] '%s': entry %d has wrong next field in auxiliary data\n"), |
| 3363 | idx, section_name (ebl, idx), cnt); |
| 3364 | break; |
| 3365 | } |
| 3366 | |
| 3367 | auxoffset += MAX (aux->vda_next, |
| 3368 | gelf_fsize (ebl->elf, ELF_T_VDAUX, 1, EV_CURRENT)); |
| 3369 | } |
| 3370 | |
| 3371 | /* Find the next offset. */ |
| 3372 | next_def: |
| 3373 | offset += def->vd_next; |
| 3374 | |
| 3375 | if ((def->vd_next != 0 || cnt > 0) |
| 3376 | && offset < auxoffset) |
| 3377 | { |
| 3378 | ERROR (gettext ("\ |
| 3379 | section [%2d] '%s': entry %d has invalid offset to next entry\n"), |
| 3380 | idx, section_name (ebl, idx), cnt); |
| 3381 | break; |
| 3382 | } |
| 3383 | |
| 3384 | if (def->vd_next == 0 && cnt > 0) |
| 3385 | { |
| 3386 | ERROR (gettext ("\ |
| 3387 | section [%2d] '%s': entry %d has zero offset to next entry, but sh_info says there are more entries\n"), |
| 3388 | idx, section_name (ebl, idx), cnt); |
| 3389 | break; |
| 3390 | } |
| 3391 | } |
| 3392 | |
| 3393 | if (!has_base) |
| 3394 | ERROR (gettext ("section [%2d] '%s': no BASE definition\n"), |
| 3395 | idx, section_name (ebl, idx)); |
| 3396 | |
| 3397 | /* Check whether the referenced names are available. */ |
| 3398 | while (namelist != NULL) |
| 3399 | { |
| 3400 | struct version_namelist *runp = version_namelist; |
| 3401 | while (runp != NULL) |
| 3402 | { |
| 3403 | if (runp->type == ver_def |
| 3404 | && strcmp (runp->name, namelist->name) == 0) |
| 3405 | break; |
| 3406 | runp = runp->next; |
| 3407 | } |
| 3408 | |
| 3409 | if (runp == NULL) |
| 3410 | ERROR (gettext ("\ |
| 3411 | section [%2d] '%s': unknown parent version '%s'\n"), |
| 3412 | idx, section_name (ebl, idx), namelist->name); |
| 3413 | |
| 3414 | namelist = namelist->next; |
| 3415 | } |
| 3416 | } |
| 3417 | |
| 3418 | static void |
| 3419 | check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 3420 | { |
| 3421 | if (shdr->sh_size == 0) |
| 3422 | { |
| 3423 | ERROR (gettext ("section [%2d] '%s': empty object attributes section\n"), |
| 3424 | idx, section_name (ebl, idx)); |
| 3425 | return; |
| 3426 | } |
| 3427 | |
| 3428 | Elf_Data *data = elf_rawdata (elf_getscn (ebl->elf, idx), NULL); |
| 3429 | if (data == NULL || data->d_size == 0 || data->d_buf == NULL) |
| 3430 | { |
| 3431 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 3432 | idx, section_name (ebl, idx)); |
| 3433 | return; |
| 3434 | } |
| 3435 | |
| 3436 | inline size_t pos (const unsigned char *p) |
| 3437 | { |
| 3438 | return p - (const unsigned char *) data->d_buf; |
| 3439 | } |
| 3440 | |
| 3441 | const unsigned char *p = data->d_buf; |
| 3442 | if (*p++ != 'A') |
| 3443 | { |
| 3444 | ERROR (gettext ("section [%2d] '%s': unrecognized attribute format\n"), |
| 3445 | idx, section_name (ebl, idx)); |
| 3446 | return; |
| 3447 | } |
| 3448 | |
| 3449 | inline size_t left (void) |
| 3450 | { |
| 3451 | return (const unsigned char *) data->d_buf + data->d_size - p; |
| 3452 | } |
| 3453 | |
| 3454 | while (left () >= 4) |
| 3455 | { |
| 3456 | uint32_t len; |
| 3457 | memcpy (&len, p, sizeof len); |
| 3458 | |
| 3459 | if (len == 0) |
| 3460 | ERROR (gettext ("\ |
| 3461 | section [%2d] '%s': offset %zu: zero length field in attribute section\n"), |
| 3462 | idx, section_name (ebl, idx), pos (p)); |
| 3463 | |
| 3464 | if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) |
| 3465 | CONVERT (len); |
| 3466 | |
| 3467 | if (len > left ()) |
| 3468 | { |
| 3469 | ERROR (gettext ("\ |
| 3470 | section [%2d] '%s': offset %zu: invalid length in attribute section\n"), |
| 3471 | idx, section_name (ebl, idx), pos (p)); |
| 3472 | break; |
| 3473 | } |
| 3474 | |
| 3475 | const unsigned char *name = p + sizeof len; |
| 3476 | p += len; |
| 3477 | |
| 3478 | unsigned const char *q = memchr (name, '\0', len); |
| 3479 | if (q == NULL) |
| 3480 | { |
| 3481 | ERROR (gettext ("\ |
| 3482 | section [%2d] '%s': offset %zu: unterminated vendor name string\n"), |
| 3483 | idx, section_name (ebl, idx), pos (p)); |
| 3484 | break; |
| 3485 | } |
| 3486 | ++q; |
| 3487 | |
| 3488 | if (q - name == sizeof "gnu" && !memcmp (name, "gnu", sizeof "gnu")) |
| 3489 | while (q < p) |
| 3490 | { |
| 3491 | unsigned const char *chunk = q; |
| 3492 | |
| 3493 | unsigned int subsection_tag; |
| 3494 | get_uleb128 (subsection_tag, q, p); |
| 3495 | |
| 3496 | if (q >= p) |
| 3497 | { |
| 3498 | ERROR (gettext ("\ |
| 3499 | section [%2d] '%s': offset %zu: endless ULEB128 in attribute subsection tag\n"), |
| 3500 | idx, section_name (ebl, idx), pos (chunk)); |
| 3501 | break; |
| 3502 | } |
| 3503 | |
| 3504 | uint32_t subsection_len; |
| 3505 | if (p - q < (ptrdiff_t) sizeof subsection_len) |
| 3506 | { |
| 3507 | ERROR (gettext ("\ |
| 3508 | section [%2d] '%s': offset %zu: truncated attribute section\n"), |
| 3509 | idx, section_name (ebl, idx), pos (q)); |
| 3510 | break; |
| 3511 | } |
| 3512 | |
| 3513 | memcpy (&subsection_len, q, sizeof subsection_len); |
| 3514 | if (subsection_len == 0) |
| 3515 | { |
| 3516 | ERROR (gettext ("\ |
| 3517 | section [%2d] '%s': offset %zu: zero length field in attribute subsection\n"), |
| 3518 | idx, section_name (ebl, idx), pos (q)); |
| 3519 | |
| 3520 | q += sizeof subsection_len; |
| 3521 | continue; |
| 3522 | } |
| 3523 | |
| 3524 | if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) |
| 3525 | CONVERT (subsection_len); |
| 3526 | |
| 3527 | /* Don't overflow, ptrdiff_t might be 32bits, but signed. */ |
| 3528 | if (p - chunk < (ptrdiff_t) subsection_len |
| 3529 | || subsection_len >= (uint32_t) PTRDIFF_MAX) |
| 3530 | { |
| 3531 | ERROR (gettext ("\ |
| 3532 | section [%2d] '%s': offset %zu: invalid length in attribute subsection\n"), |
| 3533 | idx, section_name (ebl, idx), pos (q)); |
| 3534 | break; |
| 3535 | } |
| 3536 | |
| 3537 | const unsigned char *subsection_end = chunk + subsection_len; |
| 3538 | chunk = q; |
| 3539 | q = subsection_end; |
| 3540 | |
| 3541 | if (subsection_tag != 1) /* Tag_File */ |
| 3542 | ERROR (gettext ("\ |
| 3543 | section [%2d] '%s': offset %zu: attribute subsection has unexpected tag %u\n"), |
| 3544 | idx, section_name (ebl, idx), pos (chunk), subsection_tag); |
| 3545 | else |
| 3546 | { |
| 3547 | chunk += sizeof subsection_len; |
| 3548 | while (chunk < q) |
| 3549 | { |
| 3550 | unsigned int tag; |
| 3551 | get_uleb128 (tag, chunk, q); |
| 3552 | |
| 3553 | uint64_t value = 0; |
| 3554 | const unsigned char *r = chunk; |
| 3555 | if (tag == 32 || (tag & 1) == 0) |
| 3556 | { |
| 3557 | get_uleb128 (value, r, q); |
| 3558 | if (r > q) |
| 3559 | { |
| 3560 | ERROR (gettext ("\ |
| 3561 | section [%2d] '%s': offset %zu: endless ULEB128 in attribute tag\n"), |
| 3562 | idx, section_name (ebl, idx), pos (chunk)); |
| 3563 | break; |
| 3564 | } |
| 3565 | } |
| 3566 | if (tag == 32 || (tag & 1) != 0) |
| 3567 | { |
| 3568 | r = memchr (r, '\0', q - r); |
| 3569 | if (r == NULL) |
| 3570 | { |
| 3571 | ERROR (gettext ("\ |
| 3572 | section [%2d] '%s': offset %zu: unterminated string in attribute\n"), |
| 3573 | idx, section_name (ebl, idx), pos (chunk)); |
| 3574 | break; |
| 3575 | } |
| 3576 | ++r; |
| 3577 | } |
| 3578 | |
| 3579 | const char *tag_name = NULL; |
| 3580 | const char *value_name = NULL; |
| 3581 | if (!ebl_check_object_attribute (ebl, (const char *) name, |
| 3582 | tag, value, |
| 3583 | &tag_name, &value_name)) |
| 3584 | ERROR (gettext ("\ |
| 3585 | section [%2d] '%s': offset %zu: unrecognized attribute tag %u\n"), |
| 3586 | idx, section_name (ebl, idx), pos (chunk), tag); |
| 3587 | else if ((tag & 1) == 0 && value_name == NULL) |
| 3588 | ERROR (gettext ("\ |
| 3589 | section [%2d] '%s': offset %zu: unrecognized %s attribute value %" PRIu64 "\n"), |
| 3590 | idx, section_name (ebl, idx), pos (chunk), |
| 3591 | tag_name, value); |
| 3592 | |
| 3593 | chunk = r; |
| 3594 | } |
| 3595 | } |
| 3596 | } |
| 3597 | else |
| 3598 | ERROR (gettext ("\ |
| 3599 | section [%2d] '%s': offset %zu: vendor '%s' unknown\n"), |
| 3600 | idx, section_name (ebl, idx), pos (p), name); |
| 3601 | } |
| 3602 | |
| 3603 | if (left () != 0) |
| 3604 | ERROR (gettext ("\ |
| 3605 | section [%2d] '%s': offset %zu: extra bytes after last attribute section\n"), |
| 3606 | idx, section_name (ebl, idx), pos (p)); |
| 3607 | } |
| 3608 | |
| 3609 | static bool has_loadable_segment; |
| 3610 | static bool has_interp_segment; |
| 3611 | |
| 3612 | static const struct |
| 3613 | { |
| 3614 | const char *name; |
| 3615 | size_t namelen; |
| 3616 | GElf_Word type; |
| 3617 | enum { unused, exact, atleast, exact_or_gnuld } attrflag; |
| 3618 | GElf_Word attr; |
| 3619 | GElf_Word attr2; |
| 3620 | } special_sections[] = |
| 3621 | { |
| 3622 | /* See figure 4-14 in the gABI. */ |
| 3623 | { ".bss", 5, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, |
| 3624 | { ".comment", 8, SHT_PROGBITS, atleast, 0, SHF_MERGE | SHF_STRINGS }, |
| 3625 | { ".data", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, |
| 3626 | { ".data1", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 }, |
| 3627 | { ".debug_str", 11, SHT_PROGBITS, exact_or_gnuld, SHF_MERGE | SHF_STRINGS, 0 }, |
| 3628 | { ".debug", 6, SHT_PROGBITS, exact, 0, 0 }, |
| 3629 | { ".dynamic", 9, SHT_DYNAMIC, atleast, SHF_ALLOC, SHF_WRITE }, |
| 3630 | { ".dynstr", 8, SHT_STRTAB, exact, SHF_ALLOC, 0 }, |
| 3631 | { ".dynsym", 8, SHT_DYNSYM, exact, SHF_ALLOC, 0 }, |
| 3632 | { ".fini", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, |
| 3633 | { ".fini_array", 12, SHT_FINI_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, |
| 3634 | { ".got", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more info? |
| 3635 | { ".hash", 6, SHT_HASH, exact, SHF_ALLOC, 0 }, |
| 3636 | { ".init", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, |
| 3637 | { ".init_array", 12, SHT_INIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, |
| 3638 | { ".interp", 8, SHT_PROGBITS, atleast, 0, SHF_ALLOC }, // XXX more tests? |
| 3639 | { ".line", 6, SHT_PROGBITS, exact, 0, 0 }, |
| 3640 | { ".note", 6, SHT_NOTE, atleast, 0, SHF_ALLOC }, |
| 3641 | { ".plt", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more tests |
| 3642 | { ".preinit_array", 15, SHT_PREINIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 }, |
| 3643 | { ".rela", 5, SHT_RELA, atleast, 0, SHF_ALLOC | SHF_INFO_LINK }, // XXX more tests |
| 3644 | { ".rel", 4, SHT_REL, atleast, 0, SHF_ALLOC | SHF_INFO_LINK }, // XXX more tests |
| 3645 | { ".rodata", 8, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS }, |
| 3646 | { ".rodata1", 9, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS }, |
| 3647 | { ".shstrtab", 10, SHT_STRTAB, exact, 0, 0 }, |
| 3648 | { ".strtab", 8, SHT_STRTAB, atleast, 0, SHF_ALLOC }, // XXX more tests |
| 3649 | { ".symtab", 8, SHT_SYMTAB, atleast, 0, SHF_ALLOC }, // XXX more tests |
| 3650 | { ".symtab_shndx", 14, SHT_SYMTAB_SHNDX, atleast, 0, SHF_ALLOC }, // XXX more tests |
| 3651 | { ".tbss", 6, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, |
| 3652 | { ".tdata", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, |
| 3653 | { ".tdata1", 8, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 }, |
| 3654 | { ".text", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 }, |
| 3655 | |
| 3656 | /* The following are GNU extensions. */ |
| 3657 | { ".gnu.version", 13, SHT_GNU_versym, exact, SHF_ALLOC, 0 }, |
| 3658 | { ".gnu.version_d", 15, SHT_GNU_verdef, exact, SHF_ALLOC, 0 }, |
| 3659 | { ".gnu.version_r", 15, SHT_GNU_verneed, exact, SHF_ALLOC, 0 }, |
| 3660 | { ".gnu.attributes", 16, SHT_GNU_ATTRIBUTES, exact, 0, 0 }, |
| 3661 | }; |
| 3662 | #define nspecial_sections \ |
| 3663 | (sizeof (special_sections) / sizeof (special_sections[0])) |
| 3664 | |
| 3665 | #define IS_KNOWN_SPECIAL(idx, string, prefix) \ |
| 3666 | (special_sections[idx].namelen == sizeof string - (prefix ? 1 : 0) \ |
| 3667 | && !memcmp (special_sections[idx].name, string, \ |
| 3668 | sizeof string - (prefix ? 1 : 0))) |
| 3669 | |
| 3670 | |
| 3671 | /* Indeces of some sections we need later. */ |
| 3672 | static size_t eh_frame_hdr_scnndx; |
| 3673 | static size_t eh_frame_scnndx; |
| 3674 | static size_t gcc_except_table_scnndx; |
| 3675 | |
| 3676 | |
| 3677 | static void |
| 3678 | check_sections (Ebl *ebl, GElf_Ehdr *ehdr) |
| 3679 | { |
| 3680 | if (ehdr->e_shoff == 0) |
| 3681 | /* No section header. */ |
| 3682 | return; |
| 3683 | |
| 3684 | /* Allocate array to count references in section groups. */ |
| 3685 | scnref = (int *) xcalloc (shnum, sizeof (int)); |
| 3686 | |
| 3687 | /* Check the zeroth section first. It must not have any contents |
| 3688 | and the section header must contain nonzero value at most in the |
| 3689 | sh_size and sh_link fields. */ |
| 3690 | GElf_Shdr shdr_mem; |
| 3691 | GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem); |
| 3692 | if (shdr == NULL) |
| 3693 | ERROR (gettext ("cannot get section header of zeroth section\n")); |
| 3694 | else |
| 3695 | { |
| 3696 | if (shdr->sh_name != 0) |
| 3697 | ERROR (gettext ("zeroth section has nonzero name\n")); |
| 3698 | if (shdr->sh_type != 0) |
| 3699 | ERROR (gettext ("zeroth section has nonzero type\n")); |
| 3700 | if (shdr->sh_flags != 0) |
| 3701 | ERROR (gettext ("zeroth section has nonzero flags\n")); |
| 3702 | if (shdr->sh_addr != 0) |
| 3703 | ERROR (gettext ("zeroth section has nonzero address\n")); |
| 3704 | if (shdr->sh_offset != 0) |
| 3705 | ERROR (gettext ("zeroth section has nonzero offset\n")); |
| 3706 | if (shdr->sh_addralign != 0) |
| 3707 | ERROR (gettext ("zeroth section has nonzero align value\n")); |
| 3708 | if (shdr->sh_entsize != 0) |
| 3709 | ERROR (gettext ("zeroth section has nonzero entry size value\n")); |
| 3710 | |
| 3711 | if (shdr->sh_size != 0 && ehdr->e_shnum != 0) |
| 3712 | ERROR (gettext ("\ |
| 3713 | zeroth section has nonzero size value while ELF header has nonzero shnum value\n")); |
| 3714 | |
| 3715 | if (shdr->sh_link != 0 && ehdr->e_shstrndx != SHN_XINDEX) |
| 3716 | ERROR (gettext ("\ |
| 3717 | zeroth section has nonzero link value while ELF header does not signal overflow in shstrndx\n")); |
| 3718 | |
| 3719 | if (shdr->sh_info != 0 && ehdr->e_phnum != PN_XNUM) |
| 3720 | ERROR (gettext ("\ |
| 3721 | zeroth section has nonzero link value while ELF header does not signal overflow in phnum\n")); |
| 3722 | } |
| 3723 | |
| 3724 | int *segment_flags = xcalloc (phnum, sizeof segment_flags[0]); |
| 3725 | |
| 3726 | bool dot_interp_section = false; |
| 3727 | |
| 3728 | size_t hash_idx = 0; |
| 3729 | size_t gnu_hash_idx = 0; |
| 3730 | |
| 3731 | size_t versym_scnndx = 0; |
| 3732 | for (size_t cnt = 1; cnt < shnum; ++cnt) |
| 3733 | { |
| 3734 | Elf_Scn *scn = elf_getscn (ebl->elf, cnt); |
| 3735 | shdr = gelf_getshdr (scn, &shdr_mem); |
| 3736 | if (shdr == NULL) |
| 3737 | { |
| 3738 | ERROR (gettext ("\ |
| 3739 | cannot get section header for section [%2zu] '%s': %s\n"), |
| 3740 | cnt, section_name (ebl, cnt), elf_errmsg (-1)); |
| 3741 | continue; |
| 3742 | } |
| 3743 | |
| 3744 | const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); |
| 3745 | |
| 3746 | if (scnname == NULL) |
| 3747 | ERROR (gettext ("section [%2zu]: invalid name\n"), cnt); |
| 3748 | else |
| 3749 | { |
| 3750 | /* Check whether it is one of the special sections defined in |
| 3751 | the gABI. */ |
| 3752 | size_t s; |
| 3753 | for (s = 0; s < nspecial_sections; ++s) |
| 3754 | if (strncmp (scnname, special_sections[s].name, |
| 3755 | special_sections[s].namelen) == 0) |
| 3756 | { |
| 3757 | char stbuf1[100]; |
| 3758 | char stbuf2[100]; |
| 3759 | char stbuf3[100]; |
| 3760 | |
| 3761 | GElf_Word good_type = special_sections[s].type; |
| 3762 | if (IS_KNOWN_SPECIAL (s, ".plt", false) |
| 3763 | && ebl_bss_plt_p (ebl)) |
| 3764 | good_type = SHT_NOBITS; |
| 3765 | |
| 3766 | /* In a debuginfo file, any normal section can be SHT_NOBITS. |
| 3767 | This is only invalid for DWARF sections and .shstrtab. */ |
| 3768 | if (shdr->sh_type != good_type |
| 3769 | && (shdr->sh_type != SHT_NOBITS |
| 3770 | || !is_debuginfo |
| 3771 | || IS_KNOWN_SPECIAL (s, ".debug_str", false) |
| 3772 | || IS_KNOWN_SPECIAL (s, ".debug", true) |
| 3773 | || IS_KNOWN_SPECIAL (s, ".shstrtab", false))) |
| 3774 | ERROR (gettext ("\ |
| 3775 | section [%2d] '%s' has wrong type: expected %s, is %s\n"), |
| 3776 | (int) cnt, scnname, |
| 3777 | ebl_section_type_name (ebl, special_sections[s].type, |
| 3778 | stbuf1, sizeof (stbuf1)), |
| 3779 | ebl_section_type_name (ebl, shdr->sh_type, |
| 3780 | stbuf2, sizeof (stbuf2))); |
| 3781 | |
| 3782 | if (special_sections[s].attrflag == exact |
| 3783 | || special_sections[s].attrflag == exact_or_gnuld) |
| 3784 | { |
| 3785 | /* Except for the link order, group bit and |
| 3786 | compression flag all the other bits should |
| 3787 | match exactly. */ |
| 3788 | if ((shdr->sh_flags |
| 3789 | & ~(SHF_LINK_ORDER | SHF_GROUP | SHF_COMPRESSED)) |
| 3790 | != special_sections[s].attr |
| 3791 | && (special_sections[s].attrflag == exact || !gnuld)) |
| 3792 | ERROR (gettext ("\ |
| 3793 | section [%2zu] '%s' has wrong flags: expected %s, is %s\n"), |
| 3794 | cnt, scnname, |
| 3795 | section_flags_string (special_sections[s].attr, |
| 3796 | stbuf1, sizeof (stbuf1)), |
| 3797 | section_flags_string (shdr->sh_flags |
| 3798 | & ~SHF_LINK_ORDER, |
| 3799 | stbuf2, sizeof (stbuf2))); |
| 3800 | } |
| 3801 | else if (special_sections[s].attrflag == atleast) |
| 3802 | { |
| 3803 | if ((shdr->sh_flags & special_sections[s].attr) |
| 3804 | != special_sections[s].attr |
| 3805 | || ((shdr->sh_flags |
| 3806 | & ~(SHF_LINK_ORDER | SHF_GROUP | SHF_COMPRESSED |
| 3807 | | special_sections[s].attr |
| 3808 | | special_sections[s].attr2)) |
| 3809 | != 0)) |
| 3810 | ERROR (gettext ("\ |
| 3811 | section [%2zu] '%s' has wrong flags: expected %s and possibly %s, is %s\n"), |
| 3812 | cnt, scnname, |
| 3813 | section_flags_string (special_sections[s].attr, |
| 3814 | stbuf1, sizeof (stbuf1)), |
| 3815 | section_flags_string (special_sections[s].attr2, |
| 3816 | stbuf2, sizeof (stbuf2)), |
| 3817 | section_flags_string (shdr->sh_flags |
| 3818 | & ~(SHF_LINK_ORDER |
| 3819 | | SHF_GROUP), |
| 3820 | stbuf3, sizeof (stbuf3))); |
| 3821 | } |
| 3822 | |
| 3823 | if (strcmp (scnname, ".interp") == 0) |
| 3824 | { |
| 3825 | dot_interp_section = true; |
| 3826 | |
| 3827 | if (ehdr->e_type == ET_REL) |
| 3828 | ERROR (gettext ("\ |
| 3829 | section [%2zu] '%s' present in object file\n"), |
| 3830 | cnt, scnname); |
| 3831 | |
| 3832 | if ((shdr->sh_flags & SHF_ALLOC) != 0 |
| 3833 | && !has_loadable_segment) |
| 3834 | ERROR (gettext ("\ |
| 3835 | section [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"), |
| 3836 | cnt, scnname); |
| 3837 | else if ((shdr->sh_flags & SHF_ALLOC) == 0 |
| 3838 | && has_loadable_segment) |
| 3839 | ERROR (gettext ("\ |
| 3840 | section [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"), |
| 3841 | cnt, scnname); |
| 3842 | } |
| 3843 | else |
| 3844 | { |
| 3845 | if (strcmp (scnname, ".symtab_shndx") == 0 |
| 3846 | && ehdr->e_type != ET_REL) |
| 3847 | ERROR (gettext ("\ |
| 3848 | section [%2zu] '%s' is extension section index table in non-object file\n"), |
| 3849 | cnt, scnname); |
| 3850 | |
| 3851 | /* These sections must have the SHF_ALLOC flag set iff |
| 3852 | a loadable segment is available. |
| 3853 | |
| 3854 | .relxxx |
| 3855 | .strtab |
| 3856 | .symtab |
| 3857 | .symtab_shndx |
| 3858 | |
| 3859 | Check that if there is a reference from the |
| 3860 | loaded section these sections also have the |
| 3861 | ALLOC flag set. */ |
| 3862 | #if 0 |
| 3863 | // XXX TODO |
| 3864 | if ((shdr->sh_flags & SHF_ALLOC) != 0 |
| 3865 | && !has_loadable_segment) |
| 3866 | ERROR (gettext ("\ |
| 3867 | section [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"), |
| 3868 | cnt, scnname); |
| 3869 | else if ((shdr->sh_flags & SHF_ALLOC) == 0 |
| 3870 | && has_loadable_segment) |
| 3871 | ERROR (gettext ("\ |
| 3872 | section [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"), |
| 3873 | cnt, scnname); |
| 3874 | #endif |
| 3875 | } |
| 3876 | |
| 3877 | break; |
| 3878 | } |
| 3879 | |
| 3880 | /* Remember a few special sections for later. */ |
| 3881 | if (strcmp (scnname, ".eh_frame_hdr") == 0) |
| 3882 | eh_frame_hdr_scnndx = cnt; |
| 3883 | else if (strcmp (scnname, ".eh_frame") == 0) |
| 3884 | eh_frame_scnndx = cnt; |
| 3885 | else if (strcmp (scnname, ".gcc_except_table") == 0) |
| 3886 | gcc_except_table_scnndx = cnt; |
| 3887 | } |
| 3888 | |
| 3889 | if (shdr->sh_entsize != 0 && shdr->sh_size % shdr->sh_entsize) |
| 3890 | ERROR (gettext ("\ |
| 3891 | section [%2zu] '%s': size not multiple of entry size\n"), |
| 3892 | cnt, section_name (ebl, cnt)); |
| 3893 | |
| 3894 | if (elf_strptr (ebl->elf, shstrndx, shdr->sh_name) == NULL) |
| 3895 | ERROR (gettext ("cannot get section header\n")); |
| 3896 | |
| 3897 | if (shdr->sh_type >= SHT_NUM |
| 3898 | && shdr->sh_type != SHT_GNU_ATTRIBUTES |
| 3899 | && shdr->sh_type != SHT_GNU_LIBLIST |
| 3900 | && shdr->sh_type != SHT_CHECKSUM |
| 3901 | && shdr->sh_type != SHT_GNU_verdef |
| 3902 | && shdr->sh_type != SHT_GNU_verneed |
| 3903 | && shdr->sh_type != SHT_GNU_versym |
| 3904 | && ebl_section_type_name (ebl, shdr->sh_type, NULL, 0) == NULL) |
| 3905 | ERROR (gettext ("section [%2zu] '%s' has unsupported type %d\n"), |
| 3906 | cnt, section_name (ebl, cnt), |
| 3907 | (int) shdr->sh_type); |
| 3908 | |
| 3909 | #define ALL_SH_FLAGS (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE \ |
| 3910 | | SHF_STRINGS | SHF_INFO_LINK | SHF_LINK_ORDER \ |
| 3911 | | SHF_OS_NONCONFORMING | SHF_GROUP | SHF_TLS \ |
| 3912 | | SHF_COMPRESSED) |
| 3913 | if (shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS) |
| 3914 | { |
| 3915 | GElf_Xword sh_flags = shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS; |
| 3916 | if (sh_flags & SHF_MASKPROC) |
| 3917 | { |
| 3918 | if (!ebl_machine_section_flag_check (ebl, |
| 3919 | sh_flags & SHF_MASKPROC)) |
| 3920 | ERROR (gettext ("section [%2zu] '%s'" |
| 3921 | " contains invalid processor-specific flag(s)" |
| 3922 | " %#" PRIx64 "\n"), |
| 3923 | cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC); |
| 3924 | sh_flags &= ~(GElf_Xword) SHF_MASKPROC; |
| 3925 | } |
| 3926 | if (sh_flags != 0) |
| 3927 | ERROR (gettext ("section [%2zu] '%s' contains unknown flag(s)" |
| 3928 | " %#" PRIx64 "\n"), |
| 3929 | cnt, section_name (ebl, cnt), sh_flags); |
| 3930 | } |
| 3931 | if (shdr->sh_flags & SHF_TLS) |
| 3932 | { |
| 3933 | // XXX Correct? |
| 3934 | if (shdr->sh_addr != 0 && !gnuld) |
| 3935 | ERROR (gettext ("\ |
| 3936 | section [%2zu] '%s': thread-local data sections address not zero\n"), |
| 3937 | cnt, section_name (ebl, cnt)); |
| 3938 | |
| 3939 | // XXX TODO more tests!? |
| 3940 | } |
| 3941 | |
| 3942 | if (shdr->sh_flags & SHF_COMPRESSED) |
| 3943 | { |
| 3944 | if (shdr->sh_flags & SHF_ALLOC) |
| 3945 | ERROR (gettext ("\ |
| 3946 | section [%2zu] '%s': allocated section cannot be compressed\n"), |
| 3947 | cnt, section_name (ebl, cnt)); |
| 3948 | |
| 3949 | if (shdr->sh_type == SHT_NOBITS) |
| 3950 | ERROR (gettext ("\ |
| 3951 | section [%2zu] '%s': nobits section cannot be compressed\n"), |
| 3952 | cnt, section_name (ebl, cnt)); |
| 3953 | |
| 3954 | GElf_Chdr chdr; |
| 3955 | if (gelf_getchdr (scn, &chdr) == NULL) |
| 3956 | ERROR (gettext ("\ |
| 3957 | section [%2zu] '%s': compressed section with no compression header: %s\n"), |
| 3958 | cnt, section_name (ebl, cnt), elf_errmsg (-1)); |
| 3959 | } |
| 3960 | |
| 3961 | if (shdr->sh_link >= shnum) |
| 3962 | ERROR (gettext ("\ |
| 3963 | section [%2zu] '%s': invalid section reference in link value\n"), |
| 3964 | cnt, section_name (ebl, cnt)); |
| 3965 | |
| 3966 | if (SH_INFO_LINK_P (shdr) && shdr->sh_info >= shnum) |
| 3967 | ERROR (gettext ("\ |
| 3968 | section [%2zu] '%s': invalid section reference in info value\n"), |
| 3969 | cnt, section_name (ebl, cnt)); |
| 3970 | |
| 3971 | if ((shdr->sh_flags & SHF_MERGE) == 0 |
| 3972 | && (shdr->sh_flags & SHF_STRINGS) != 0 |
| 3973 | && be_strict) |
| 3974 | ERROR (gettext ("\ |
| 3975 | section [%2zu] '%s': strings flag set without merge flag\n"), |
| 3976 | cnt, section_name (ebl, cnt)); |
| 3977 | |
| 3978 | if ((shdr->sh_flags & SHF_MERGE) != 0 && shdr->sh_entsize == 0) |
| 3979 | ERROR (gettext ("\ |
| 3980 | section [%2zu] '%s': merge flag set but entry size is zero\n"), |
| 3981 | cnt, section_name (ebl, cnt)); |
| 3982 | |
| 3983 | if (shdr->sh_flags & SHF_GROUP) |
| 3984 | check_scn_group (ebl, cnt); |
| 3985 | |
| 3986 | if (shdr->sh_flags & SHF_EXECINSTR) |
| 3987 | { |
| 3988 | switch (shdr->sh_type) |
| 3989 | { |
| 3990 | case SHT_PROGBITS: |
| 3991 | break; |
| 3992 | |
| 3993 | case SHT_NOBITS: |
| 3994 | if (is_debuginfo) |
| 3995 | break; |
| 3996 | FALLTHROUGH; |
| 3997 | default: |
| 3998 | ERROR (gettext ("\ |
| 3999 | section [%2zu] '%s' has unexpected type %d for an executable section\n"), |
| 4000 | cnt, section_name (ebl, cnt), shdr->sh_type); |
| 4001 | break; |
| 4002 | } |
| 4003 | |
| 4004 | if (shdr->sh_flags & SHF_WRITE) |
| 4005 | { |
| 4006 | if (is_debuginfo && shdr->sh_type != SHT_NOBITS) |
| 4007 | ERROR (gettext ("\ |
| 4008 | section [%2zu] '%s' must be of type NOBITS in debuginfo files\n"), |
| 4009 | cnt, section_name (ebl, cnt)); |
| 4010 | |
| 4011 | if (!is_debuginfo |
| 4012 | && !ebl_check_special_section (ebl, cnt, shdr, |
| 4013 | section_name (ebl, cnt))) |
| 4014 | ERROR (gettext ("\ |
| 4015 | section [%2zu] '%s' is both executable and writable\n"), |
| 4016 | cnt, section_name (ebl, cnt)); |
| 4017 | } |
| 4018 | } |
| 4019 | |
| 4020 | if (ehdr->e_type != ET_REL && (shdr->sh_flags & SHF_ALLOC) != 0 |
| 4021 | && !is_debuginfo) |
| 4022 | { |
| 4023 | /* Make sure the section is contained in a loaded segment |
| 4024 | and that the initialization part matches NOBITS sections. */ |
| 4025 | unsigned int pcnt; |
| 4026 | GElf_Phdr phdr_mem; |
| 4027 | GElf_Phdr *phdr; |
| 4028 | |
| 4029 | for (pcnt = 0; pcnt < phnum; ++pcnt) |
| 4030 | if ((phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem)) != NULL |
| 4031 | && ((phdr->p_type == PT_LOAD |
| 4032 | && (shdr->sh_flags & SHF_TLS) == 0) |
| 4033 | || (phdr->p_type == PT_TLS |
| 4034 | && (shdr->sh_flags & SHF_TLS) != 0)) |
| 4035 | && phdr->p_offset <= shdr->sh_offset |
| 4036 | && ((shdr->sh_offset - phdr->p_offset <= phdr->p_filesz |
| 4037 | && (shdr->sh_offset - phdr->p_offset < phdr->p_filesz |
| 4038 | || shdr->sh_size == 0)) |
| 4039 | || (shdr->sh_offset - phdr->p_offset < phdr->p_memsz |
| 4040 | && shdr->sh_type == SHT_NOBITS))) |
| 4041 | { |
| 4042 | /* Found the segment. */ |
| 4043 | if (phdr->p_offset + phdr->p_memsz |
| 4044 | < shdr->sh_offset + shdr->sh_size) |
| 4045 | ERROR (gettext ("\ |
| 4046 | section [%2zu] '%s' not fully contained in segment of program header entry %d\n"), |
| 4047 | cnt, section_name (ebl, cnt), pcnt); |
| 4048 | |
| 4049 | if (shdr->sh_type == SHT_NOBITS) |
| 4050 | { |
| 4051 | if (shdr->sh_offset < phdr->p_offset + phdr->p_filesz |
| 4052 | && !is_debuginfo) |
| 4053 | { |
| 4054 | if (!gnuld) |
| 4055 | ERROR (gettext ("\ |
| 4056 | section [%2zu] '%s' has type NOBITS but is read from the file in segment of program header entry %d\n"), |
| 4057 | cnt, section_name (ebl, cnt), pcnt); |
| 4058 | else |
| 4059 | { |
| 4060 | /* This is truly horrible. GNU ld might put a |
| 4061 | NOBITS section in the middle of a PT_LOAD |
| 4062 | segment, assuming the next gap in the file |
| 4063 | actually consists of zero bits... |
| 4064 | So it really is like a PROGBITS section |
| 4065 | where the data is all zeros. Check those |
| 4066 | zero bytes are really there. */ |
| 4067 | bool bad; |
| 4068 | Elf_Data *databits; |
| 4069 | databits = elf_getdata_rawchunk (ebl->elf, |
| 4070 | shdr->sh_offset, |
| 4071 | shdr->sh_size, |
| 4072 | ELF_T_BYTE); |
| 4073 | bad = (databits == NULL |
| 4074 | || databits->d_size != shdr->sh_size); |
| 4075 | for (size_t idx = 0; |
| 4076 | idx < databits->d_size && ! bad; |
| 4077 | idx++) |
| 4078 | bad = ((char *) databits->d_buf)[idx] != 0; |
| 4079 | |
| 4080 | if (bad) |
| 4081 | ERROR (gettext ("\ |
| 4082 | section [%2zu] '%s' has type NOBITS but is read from the file in segment of program header entry %d and file contents is non-zero\n"), |
| 4083 | cnt, section_name (ebl, cnt), pcnt); |
| 4084 | } |
| 4085 | } |
| 4086 | } |
| 4087 | else |
| 4088 | { |
| 4089 | const GElf_Off end = phdr->p_offset + phdr->p_filesz; |
| 4090 | if (shdr->sh_offset > end || |
| 4091 | (shdr->sh_offset == end && shdr->sh_size != 0)) |
| 4092 | ERROR (gettext ("\ |
| 4093 | section [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"), |
| 4094 | cnt, section_name (ebl, cnt), pcnt); |
| 4095 | } |
| 4096 | |
| 4097 | if (shdr->sh_type != SHT_NOBITS) |
| 4098 | { |
| 4099 | if ((shdr->sh_flags & SHF_EXECINSTR) != 0) |
| 4100 | { |
| 4101 | segment_flags[pcnt] |= PF_X; |
| 4102 | if ((phdr->p_flags & PF_X) == 0) |
| 4103 | ERROR (gettext ("\ |
| 4104 | section [%2zu] '%s' is executable in nonexecutable segment %d\n"), |
| 4105 | cnt, section_name (ebl, cnt), pcnt); |
| 4106 | } |
| 4107 | |
| 4108 | if ((shdr->sh_flags & SHF_WRITE) != 0) |
| 4109 | { |
| 4110 | segment_flags[pcnt] |= PF_W; |
| 4111 | if (0 /* XXX vdso images have this */ |
| 4112 | && (phdr->p_flags & PF_W) == 0) |
| 4113 | ERROR (gettext ("\ |
| 4114 | section [%2zu] '%s' is writable in unwritable segment %d\n"), |
| 4115 | cnt, section_name (ebl, cnt), pcnt); |
| 4116 | } |
| 4117 | } |
| 4118 | |
| 4119 | break; |
| 4120 | } |
| 4121 | |
| 4122 | if (pcnt == phnum) |
| 4123 | ERROR (gettext ("\ |
| 4124 | section [%2zu] '%s': alloc flag set but section not in any loaded segment\n"), |
| 4125 | cnt, section_name (ebl, cnt)); |
| 4126 | } |
| 4127 | |
| 4128 | if (cnt == shstrndx && shdr->sh_type != SHT_STRTAB) |
| 4129 | ERROR (gettext ("\ |
| 4130 | section [%2zu] '%s': ELF header says this is the section header string table but type is not SHT_TYPE\n"), |
| 4131 | cnt, section_name (ebl, cnt)); |
| 4132 | |
| 4133 | switch (shdr->sh_type) |
| 4134 | { |
| 4135 | case SHT_DYNSYM: |
| 4136 | if (ehdr->e_type == ET_REL) |
| 4137 | ERROR (gettext ("\ |
| 4138 | section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"), |
| 4139 | cnt, section_name (ebl, cnt)); |
| 4140 | FALLTHROUGH; |
| 4141 | case SHT_SYMTAB: |
| 4142 | check_symtab (ebl, ehdr, shdr, cnt); |
| 4143 | break; |
| 4144 | |
| 4145 | case SHT_RELA: |
| 4146 | check_rela (ebl, ehdr, shdr, cnt); |
| 4147 | break; |
| 4148 | |
| 4149 | case SHT_REL: |
| 4150 | check_rel (ebl, ehdr, shdr, cnt); |
| 4151 | break; |
| 4152 | |
| 4153 | case SHT_DYNAMIC: |
| 4154 | check_dynamic (ebl, ehdr, shdr, cnt); |
| 4155 | break; |
| 4156 | |
| 4157 | case SHT_SYMTAB_SHNDX: |
| 4158 | check_symtab_shndx (ebl, ehdr, shdr, cnt); |
| 4159 | break; |
| 4160 | |
| 4161 | case SHT_HASH: |
| 4162 | check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt); |
| 4163 | hash_idx = cnt; |
| 4164 | break; |
| 4165 | |
| 4166 | case SHT_GNU_HASH: |
| 4167 | check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt); |
| 4168 | gnu_hash_idx = cnt; |
| 4169 | break; |
| 4170 | |
| 4171 | case SHT_NULL: |
| 4172 | check_null (ebl, shdr, cnt); |
| 4173 | break; |
| 4174 | |
| 4175 | case SHT_GROUP: |
| 4176 | check_group (ebl, ehdr, shdr, cnt); |
| 4177 | break; |
| 4178 | |
| 4179 | case SHT_NOTE: |
| 4180 | check_note_section (ebl, ehdr, shdr, cnt); |
| 4181 | break; |
| 4182 | |
| 4183 | case SHT_GNU_versym: |
| 4184 | /* We cannot process this section now since we have no guarantee |
| 4185 | that the verneed and verdef sections have already been read. |
| 4186 | Just remember the section index. */ |
| 4187 | if (versym_scnndx != 0) |
| 4188 | ERROR (gettext ("more than one version symbol table present\n")); |
| 4189 | versym_scnndx = cnt; |
| 4190 | break; |
| 4191 | |
| 4192 | case SHT_GNU_verneed: |
| 4193 | check_verneed (ebl, shdr, cnt); |
| 4194 | break; |
| 4195 | |
| 4196 | case SHT_GNU_verdef: |
| 4197 | check_verdef (ebl, shdr, cnt); |
| 4198 | break; |
| 4199 | |
| 4200 | case SHT_GNU_ATTRIBUTES: |
| 4201 | check_attributes (ebl, ehdr, shdr, cnt); |
| 4202 | break; |
| 4203 | |
| 4204 | default: |
| 4205 | /* Nothing. */ |
| 4206 | break; |
| 4207 | } |
| 4208 | } |
| 4209 | |
| 4210 | if (has_interp_segment && !dot_interp_section) |
| 4211 | ERROR (gettext ("INTERP program header entry but no .interp section\n")); |
| 4212 | |
| 4213 | if (!is_debuginfo) |
| 4214 | for (unsigned int pcnt = 0; pcnt < phnum; ++pcnt) |
| 4215 | { |
| 4216 | GElf_Phdr phdr_mem; |
| 4217 | GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem); |
| 4218 | if (phdr != NULL && (phdr->p_type == PT_LOAD || phdr->p_type == PT_TLS)) |
| 4219 | { |
| 4220 | if ((phdr->p_flags & PF_X) != 0 |
| 4221 | && (segment_flags[pcnt] & PF_X) == 0) |
| 4222 | ERROR (gettext ("\ |
| 4223 | loadable segment [%u] is executable but contains no executable sections\n"), |
| 4224 | pcnt); |
| 4225 | |
| 4226 | if ((phdr->p_flags & PF_W) != 0 |
| 4227 | && (segment_flags[pcnt] & PF_W) == 0) |
| 4228 | ERROR (gettext ("\ |
| 4229 | loadable segment [%u] is writable but contains no writable sections\n"), |
| 4230 | pcnt); |
| 4231 | } |
| 4232 | } |
| 4233 | |
| 4234 | free (segment_flags); |
| 4235 | |
| 4236 | if (version_namelist != NULL) |
| 4237 | { |
| 4238 | if (versym_scnndx == 0) |
| 4239 | ERROR (gettext ("\ |
| 4240 | no .gnu.versym section present but .gnu.versym_d or .gnu.versym_r section exist\n")); |
| 4241 | else |
| 4242 | check_versym (ebl, versym_scnndx); |
| 4243 | |
| 4244 | /* Check for duplicate index numbers. */ |
| 4245 | do |
| 4246 | { |
| 4247 | struct version_namelist *runp = version_namelist->next; |
| 4248 | while (runp != NULL) |
| 4249 | { |
| 4250 | if (version_namelist->ndx == runp->ndx) |
| 4251 | { |
| 4252 | ERROR (gettext ("duplicate version index %d\n"), |
| 4253 | (int) version_namelist->ndx); |
| 4254 | break; |
| 4255 | } |
| 4256 | runp = runp->next; |
| 4257 | } |
| 4258 | |
| 4259 | struct version_namelist *old = version_namelist; |
| 4260 | version_namelist = version_namelist->next; |
| 4261 | free (old); |
| 4262 | } |
| 4263 | while (version_namelist != NULL); |
| 4264 | } |
| 4265 | else if (versym_scnndx != 0) |
| 4266 | ERROR (gettext ("\ |
| 4267 | .gnu.versym section present without .gnu.versym_d or .gnu.versym_r\n")); |
| 4268 | |
| 4269 | if (hash_idx != 0 && gnu_hash_idx != 0) |
| 4270 | compare_hash_gnu_hash (ebl, ehdr, hash_idx, gnu_hash_idx); |
| 4271 | |
| 4272 | free (scnref); |
| 4273 | } |
| 4274 | |
| 4275 | |
| 4276 | static GElf_Off |
| 4277 | check_note_data (Ebl *ebl, const GElf_Ehdr *ehdr, |
| 4278 | Elf_Data *data, int shndx, int phndx, GElf_Off start) |
| 4279 | { |
| 4280 | size_t offset = 0; |
| 4281 | size_t last_offset = 0; |
| 4282 | GElf_Nhdr nhdr; |
| 4283 | size_t name_offset; |
| 4284 | size_t desc_offset; |
| 4285 | while (offset < data->d_size |
| 4286 | && (offset = gelf_getnote (data, offset, |
| 4287 | &nhdr, &name_offset, &desc_offset)) > 0) |
| 4288 | { |
| 4289 | last_offset = offset; |
| 4290 | |
| 4291 | /* Make sure it is one of the note types we know about. */ |
| 4292 | if (ehdr->e_type == ET_CORE) |
| 4293 | switch (nhdr.n_type) |
| 4294 | { |
| 4295 | case NT_PRSTATUS: |
| 4296 | case NT_FPREGSET: |
| 4297 | case NT_PRPSINFO: |
| 4298 | case NT_TASKSTRUCT: /* NT_PRXREG on Solaris. */ |
| 4299 | case NT_PLATFORM: |
| 4300 | case NT_AUXV: |
| 4301 | case NT_GWINDOWS: |
| 4302 | case NT_ASRS: |
| 4303 | case NT_PSTATUS: |
| 4304 | case NT_PSINFO: |
| 4305 | case NT_PRCRED: |
| 4306 | case NT_UTSNAME: |
| 4307 | case NT_LWPSTATUS: |
| 4308 | case NT_LWPSINFO: |
| 4309 | case NT_PRFPXREG: |
| 4310 | /* Known type. */ |
| 4311 | break; |
| 4312 | |
| 4313 | default: |
| 4314 | if (shndx == 0) |
| 4315 | ERROR (gettext ("\ |
| 4316 | phdr[%d]: unknown core file note type %" PRIu32 " at offset %" PRIu64 "\n"), |
| 4317 | phndx, (uint32_t) nhdr.n_type, start + offset); |
| 4318 | else |
| 4319 | ERROR (gettext ("\ |
| 4320 | section [%2d] '%s': unknown core file note type %" PRIu32 |
| 4321 | " at offset %zu\n"), |
| 4322 | shndx, section_name (ebl, shndx), |
| 4323 | (uint32_t) nhdr.n_type, offset); |
| 4324 | } |
| 4325 | else |
| 4326 | switch (nhdr.n_type) |
| 4327 | { |
| 4328 | case NT_GNU_ABI_TAG: |
| 4329 | case NT_GNU_HWCAP: |
| 4330 | case NT_GNU_BUILD_ID: |
| 4331 | case NT_GNU_GOLD_VERSION: |
| 4332 | break; |
| 4333 | |
| 4334 | case 0: |
| 4335 | /* Linux vDSOs use a type 0 note for the kernel version word. */ |
| 4336 | if (nhdr.n_namesz == sizeof "Linux" |
| 4337 | && !memcmp (data->d_buf + name_offset, "Linux", sizeof "Linux")) |
| 4338 | break; |
| 4339 | FALLTHROUGH; |
| 4340 | default: |
| 4341 | if (shndx == 0) |
| 4342 | ERROR (gettext ("\ |
| 4343 | phdr[%d]: unknown object file note type %" PRIu32 " at offset %zu\n"), |
| 4344 | phndx, (uint32_t) nhdr.n_type, offset); |
| 4345 | else |
| 4346 | ERROR (gettext ("\ |
| 4347 | section [%2d] '%s': unknown object file note type %" PRIu32 |
| 4348 | " at offset %zu\n"), |
| 4349 | shndx, section_name (ebl, shndx), |
| 4350 | (uint32_t) nhdr.n_type, offset); |
| 4351 | } |
| 4352 | } |
| 4353 | |
| 4354 | return last_offset; |
| 4355 | } |
| 4356 | |
| 4357 | |
| 4358 | static void |
| 4359 | check_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt) |
| 4360 | { |
| 4361 | if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL |
| 4362 | && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) |
| 4363 | ERROR (gettext ("\ |
| 4364 | phdr[%d]: no note entries defined for the type of file\n"), |
| 4365 | cnt); |
| 4366 | |
| 4367 | if (is_debuginfo) |
| 4368 | /* The p_offset values in a separate debug file are bogus. */ |
| 4369 | return; |
| 4370 | |
| 4371 | if (phdr->p_filesz == 0) |
| 4372 | return; |
| 4373 | |
| 4374 | GElf_Off notes_size = 0; |
| 4375 | Elf_Data *data = elf_getdata_rawchunk (ebl->elf, |
| 4376 | phdr->p_offset, phdr->p_filesz, |
| 4377 | ELF_T_NHDR); |
| 4378 | if (data != NULL && data->d_buf != NULL) |
| 4379 | notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset); |
| 4380 | |
| 4381 | if (notes_size == 0) |
| 4382 | ERROR (gettext ("phdr[%d]: cannot get content of note section: %s\n"), |
| 4383 | cnt, elf_errmsg (-1)); |
| 4384 | else if (notes_size != phdr->p_filesz) |
| 4385 | ERROR (gettext ("phdr[%d]: extra %" PRIu64 " bytes after last note\n"), |
| 4386 | cnt, phdr->p_filesz - notes_size); |
| 4387 | } |
| 4388 | |
| 4389 | |
| 4390 | static void |
| 4391 | check_note_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) |
| 4392 | { |
| 4393 | if (shdr->sh_size == 0) |
| 4394 | return; |
| 4395 | |
| 4396 | Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL); |
| 4397 | if (data == NULL || data->d_buf == NULL) |
| 4398 | { |
| 4399 | ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), |
| 4400 | idx, section_name (ebl, idx)); |
| 4401 | return; |
| 4402 | } |
| 4403 | |
| 4404 | if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL |
| 4405 | && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) |
| 4406 | ERROR (gettext ("\ |
| 4407 | section [%2d] '%s': no note entries defined for the type of file\n"), |
| 4408 | idx, section_name (ebl, idx)); |
| 4409 | |
| 4410 | GElf_Off notes_size = check_note_data (ebl, ehdr, data, idx, 0, 0); |
| 4411 | |
| 4412 | if (notes_size == 0) |
| 4413 | ERROR (gettext ("section [%2d] '%s': cannot get content of note section\n"), |
| 4414 | idx, section_name (ebl, idx)); |
| 4415 | else if (notes_size != shdr->sh_size) |
| 4416 | ERROR (gettext ("section [%2d] '%s': extra %" PRIu64 |
| 4417 | " bytes after last note\n"), |
| 4418 | idx, section_name (ebl, idx), shdr->sh_size - notes_size); |
| 4419 | } |
| 4420 | |
| 4421 | |
| 4422 | /* Index of the PT_GNU_EH_FRAME program eader entry. */ |
| 4423 | static int pt_gnu_eh_frame_pndx; |
| 4424 | |
| 4425 | |
| 4426 | static void |
| 4427 | check_program_header (Ebl *ebl, GElf_Ehdr *ehdr) |
| 4428 | { |
| 4429 | if (ehdr->e_phoff == 0) |
| 4430 | return; |
| 4431 | |
| 4432 | if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN |
| 4433 | && ehdr->e_type != ET_CORE) |
| 4434 | ERROR (gettext ("\ |
| 4435 | only executables, shared objects, and core files can have program headers\n")); |
| 4436 | |
| 4437 | int num_pt_interp = 0; |
| 4438 | int num_pt_tls = 0; |
| 4439 | int num_pt_relro = 0; |
| 4440 | |
| 4441 | for (unsigned int cnt = 0; cnt < phnum; ++cnt) |
| 4442 | { |
| 4443 | GElf_Phdr phdr_mem; |
| 4444 | GElf_Phdr *phdr; |
| 4445 | |
| 4446 | phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem); |
| 4447 | if (phdr == NULL) |
| 4448 | { |
| 4449 | ERROR (gettext ("cannot get program header entry %d: %s\n"), |
| 4450 | cnt, elf_errmsg (-1)); |
| 4451 | continue; |
| 4452 | } |
| 4453 | |
| 4454 | if (phdr->p_type >= PT_NUM && phdr->p_type != PT_GNU_EH_FRAME |
| 4455 | && phdr->p_type != PT_GNU_STACK && phdr->p_type != PT_GNU_RELRO |
| 4456 | /* Check for a known machine-specific type. */ |
| 4457 | && ebl_segment_type_name (ebl, phdr->p_type, NULL, 0) == NULL) |
| 4458 | ERROR (gettext ("\ |
| 4459 | program header entry %d: unknown program header entry type %#" PRIx64 "\n"), |
| 4460 | cnt, (uint64_t) phdr->p_type); |
| 4461 | |
| 4462 | if (phdr->p_type == PT_LOAD) |
| 4463 | has_loadable_segment = true; |
| 4464 | else if (phdr->p_type == PT_INTERP) |
| 4465 | { |
| 4466 | if (++num_pt_interp != 1) |
| 4467 | { |
| 4468 | if (num_pt_interp == 2) |
| 4469 | ERROR (gettext ("\ |
| 4470 | more than one INTERP entry in program header\n")); |
| 4471 | } |
| 4472 | has_interp_segment = true; |
| 4473 | } |
| 4474 | else if (phdr->p_type == PT_TLS) |
| 4475 | { |
| 4476 | if (++num_pt_tls == 2) |
| 4477 | ERROR (gettext ("more than one TLS entry in program header\n")); |
| 4478 | } |
| 4479 | else if (phdr->p_type == PT_NOTE) |
| 4480 | check_note (ebl, ehdr, phdr, cnt); |
| 4481 | else if (phdr->p_type == PT_DYNAMIC) |
| 4482 | { |
| 4483 | if (ehdr->e_type == ET_EXEC && ! has_interp_segment) |
| 4484 | ERROR (gettext ("\ |
| 4485 | static executable cannot have dynamic sections\n")); |
| 4486 | else |
| 4487 | { |
| 4488 | /* Check that the .dynamic section, if it exists, has |
| 4489 | the same address. */ |
| 4490 | Elf_Scn *scn = NULL; |
| 4491 | while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) |
| 4492 | { |
| 4493 | GElf_Shdr shdr_mem; |
| 4494 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); |
| 4495 | if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC) |
| 4496 | { |
| 4497 | if (phdr->p_offset != shdr->sh_offset) |
| 4498 | ERROR (gettext ("\ |
| 4499 | dynamic section reference in program header has wrong offset\n")); |
| 4500 | if (phdr->p_memsz != shdr->sh_size) |
| 4501 | ERROR (gettext ("\ |
| 4502 | dynamic section size mismatch in program and section header\n")); |
| 4503 | break; |
| 4504 | } |
| 4505 | } |
| 4506 | } |
| 4507 | } |
| 4508 | else if (phdr->p_type == PT_GNU_RELRO) |
| 4509 | { |
| 4510 | if (++num_pt_relro == 2) |
| 4511 | ERROR (gettext ("\ |
| 4512 | more than one GNU_RELRO entry in program header\n")); |
| 4513 | else |
| 4514 | { |
| 4515 | /* Check that the region is in a writable segment. */ |
| 4516 | unsigned int inner; |
| 4517 | for (inner = 0; inner < phnum; ++inner) |
| 4518 | { |
| 4519 | GElf_Phdr phdr2_mem; |
| 4520 | GElf_Phdr *phdr2; |
| 4521 | |
| 4522 | phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem); |
| 4523 | if (phdr2 == NULL) |
| 4524 | continue; |
| 4525 | |
| 4526 | if (phdr2->p_type == PT_LOAD |
| 4527 | && phdr->p_vaddr >= phdr2->p_vaddr |
| 4528 | && (phdr->p_vaddr + phdr->p_memsz |
| 4529 | <= phdr2->p_vaddr + phdr2->p_memsz)) |
| 4530 | { |
| 4531 | if ((phdr2->p_flags & PF_W) == 0) |
| 4532 | ERROR (gettext ("\ |
| 4533 | loadable segment GNU_RELRO applies to is not writable\n")); |
| 4534 | /* Unless fully covered, relro flags could be a |
| 4535 | subset of the phdrs2 flags. For example the load |
| 4536 | segment could also have PF_X set. */ |
| 4537 | if (phdr->p_vaddr == phdr2->p_vaddr |
| 4538 | && (phdr->p_vaddr + phdr->p_memsz |
| 4539 | == phdr2->p_vaddr + phdr2->p_memsz)) |
| 4540 | { |
| 4541 | if ((phdr2->p_flags & ~PF_W) |
| 4542 | != (phdr->p_flags & ~PF_W)) |
| 4543 | ERROR (gettext ("\ |
| 4544 | loadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"), |
| 4545 | cnt, inner); |
| 4546 | } |
| 4547 | else |
| 4548 | { |
| 4549 | if ((phdr->p_flags & ~phdr2->p_flags) != 0) |
| 4550 | ERROR (gettext ("\ |
| 4551 | GNU_RELRO [%u] flags are not a subset of the loadable segment [%u] flags\n"), |
| 4552 | inner, cnt); |
| 4553 | } |
| 4554 | break; |
| 4555 | } |
| 4556 | } |
| 4557 | |
| 4558 | if (inner >= phnum) |
| 4559 | ERROR (gettext ("\ |
| 4560 | %s segment not contained in a loaded segment\n"), "GNU_RELRO"); |
| 4561 | } |
| 4562 | } |
| 4563 | else if (phdr->p_type == PT_PHDR) |
| 4564 | { |
| 4565 | /* Check that the region is in a writable segment. */ |
| 4566 | unsigned int inner; |
| 4567 | for (inner = 0; inner < phnum; ++inner) |
| 4568 | { |
| 4569 | GElf_Phdr phdr2_mem; |
| 4570 | GElf_Phdr *phdr2; |
| 4571 | |
| 4572 | phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem); |
| 4573 | if (phdr2 != NULL |
| 4574 | && phdr2->p_type == PT_LOAD |
| 4575 | && phdr->p_vaddr >= phdr2->p_vaddr |
| 4576 | && (phdr->p_vaddr + phdr->p_memsz |
| 4577 | <= phdr2->p_vaddr + phdr2->p_memsz)) |
| 4578 | break; |
| 4579 | } |
| 4580 | |
| 4581 | if (inner >= phnum) |
| 4582 | ERROR (gettext ("\ |
| 4583 | %s segment not contained in a loaded segment\n"), "PHDR"); |
| 4584 | |
| 4585 | /* Check that offset in segment corresponds to offset in ELF |
| 4586 | header. */ |
| 4587 | if (phdr->p_offset != ehdr->e_phoff) |
| 4588 | ERROR (gettext ("\ |
| 4589 | program header offset in ELF header and PHDR entry do not match")); |
| 4590 | } |
| 4591 | else if (phdr->p_type == PT_GNU_EH_FRAME) |
| 4592 | { |
| 4593 | /* If there is an .eh_frame_hdr section it must be |
| 4594 | referenced by this program header entry. */ |
| 4595 | Elf_Scn *scn = NULL; |
| 4596 | GElf_Shdr shdr_mem; |
| 4597 | GElf_Shdr *shdr = NULL; |
| 4598 | bool any = false; |
| 4599 | while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) |
| 4600 | { |
| 4601 | any = true; |
| 4602 | shdr = gelf_getshdr (scn, &shdr_mem); |
| 4603 | if (shdr != NULL |
| 4604 | && shdr->sh_type == (is_debuginfo |
| 4605 | ? SHT_NOBITS : SHT_PROGBITS) |
| 4606 | && elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL |
| 4607 | && ! strcmp (".eh_frame_hdr", |
| 4608 | elf_strptr (ebl->elf, shstrndx, shdr->sh_name))) |
| 4609 | { |
| 4610 | if (! is_debuginfo) |
| 4611 | { |
| 4612 | if (phdr->p_offset != shdr->sh_offset) |
| 4613 | ERROR (gettext ("\ |
| 4614 | call frame search table reference in program header has wrong offset\n")); |
| 4615 | if (phdr->p_memsz != shdr->sh_size) |
| 4616 | ERROR (gettext ("\ |
| 4617 | call frame search table size mismatch in program and section header\n")); |
| 4618 | } |
| 4619 | break; |
| 4620 | } |
| 4621 | } |
| 4622 | |
| 4623 | if (scn == NULL) |
| 4624 | { |
| 4625 | /* If there is no section header table we don't |
| 4626 | complain. But if there is one there should be an |
| 4627 | entry for .eh_frame_hdr. */ |
| 4628 | if (any) |
| 4629 | ERROR (gettext ("\ |
| 4630 | PT_GNU_EH_FRAME present but no .eh_frame_hdr section\n")); |
| 4631 | } |
| 4632 | else |
| 4633 | { |
| 4634 | /* The section must be allocated and not be writable and |
| 4635 | executable. */ |
| 4636 | if ((phdr->p_flags & PF_R) == 0) |
| 4637 | ERROR (gettext ("\ |
| 4638 | call frame search table must be allocated\n")); |
| 4639 | else if (shdr != NULL && (shdr->sh_flags & SHF_ALLOC) == 0) |
| 4640 | ERROR (gettext ("\ |
| 4641 | section [%2zu] '%s' must be allocated\n"), elf_ndxscn (scn), ".eh_frame_hdr"); |
| 4642 | |
| 4643 | if ((phdr->p_flags & PF_W) != 0) |
| 4644 | ERROR (gettext ("\ |
| 4645 | call frame search table must not be writable\n")); |
| 4646 | else if (shdr != NULL && (shdr->sh_flags & SHF_WRITE) != 0) |
| 4647 | ERROR (gettext ("\ |
| 4648 | section [%2zu] '%s' must not be writable\n"), |
| 4649 | elf_ndxscn (scn), ".eh_frame_hdr"); |
| 4650 | |
| 4651 | if ((phdr->p_flags & PF_X) != 0) |
| 4652 | ERROR (gettext ("\ |
| 4653 | call frame search table must not be executable\n")); |
| 4654 | else if (shdr != NULL && (shdr->sh_flags & SHF_EXECINSTR) != 0) |
| 4655 | ERROR (gettext ("\ |
| 4656 | section [%2zu] '%s' must not be executable\n"), |
| 4657 | elf_ndxscn (scn), ".eh_frame_hdr"); |
| 4658 | } |
| 4659 | |
| 4660 | /* Remember which entry this is. */ |
| 4661 | pt_gnu_eh_frame_pndx = cnt; |
| 4662 | } |
| 4663 | |
| 4664 | if (phdr->p_filesz > phdr->p_memsz |
| 4665 | && (phdr->p_memsz != 0 || phdr->p_type != PT_NOTE)) |
| 4666 | ERROR (gettext ("\ |
| 4667 | program header entry %d: file size greater than memory size\n"), |
| 4668 | cnt); |
| 4669 | |
| 4670 | if (phdr->p_align > 1) |
| 4671 | { |
| 4672 | if (!powerof2 (phdr->p_align)) |
| 4673 | ERROR (gettext ("\ |
| 4674 | program header entry %d: alignment not a power of 2\n"), cnt); |
| 4675 | else if ((phdr->p_vaddr - phdr->p_offset) % phdr->p_align != 0) |
| 4676 | ERROR (gettext ("\ |
| 4677 | program header entry %d: file offset and virtual address not module of alignment\n"), cnt); |
| 4678 | } |
| 4679 | } |
| 4680 | } |
| 4681 | |
| 4682 | |
| 4683 | static void |
| 4684 | check_exception_data (Ebl *ebl __attribute__ ((unused)), |
| 4685 | GElf_Ehdr *ehdr __attribute__ ((unused))) |
| 4686 | { |
| 4687 | if ((ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) |
| 4688 | && pt_gnu_eh_frame_pndx == 0 && eh_frame_hdr_scnndx != 0) |
| 4689 | ERROR (gettext ("executable/DSO with .eh_frame_hdr section does not have " |
| 4690 | "a PT_GNU_EH_FRAME program header entry")); |
| 4691 | } |
| 4692 | |
| 4693 | |
| 4694 | /* Process one file. */ |
| 4695 | static void |
| 4696 | process_elf_file (Elf *elf, const char *prefix, const char *suffix, |
| 4697 | const char *fname, size_t size, bool only_one) |
| 4698 | { |
| 4699 | /* Reset variables. */ |
| 4700 | ndynamic = 0; |
| 4701 | nverneed = 0; |
| 4702 | nverdef = 0; |
| 4703 | textrel = false; |
| 4704 | needed_textrel = false; |
| 4705 | has_loadable_segment = false; |
| 4706 | has_interp_segment = false; |
| 4707 | |
| 4708 | GElf_Ehdr ehdr_mem; |
| 4709 | GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); |
| 4710 | Ebl *ebl; |
| 4711 | |
| 4712 | /* Print the file name. */ |
| 4713 | if (!only_one) |
| 4714 | { |
| 4715 | if (prefix != NULL) |
| 4716 | printf ("\n%s(%s)%s:\n", prefix, fname, suffix); |
| 4717 | else |
| 4718 | printf ("\n%s:\n", fname); |
| 4719 | } |
| 4720 | |
| 4721 | if (ehdr == NULL) |
| 4722 | { |
| 4723 | ERROR (gettext ("cannot read ELF header: %s\n"), elf_errmsg (-1)); |
| 4724 | return; |
| 4725 | } |
| 4726 | |
| 4727 | ebl = ebl_openbackend (elf); |
| 4728 | /* If there is no appropriate backend library we cannot test |
| 4729 | architecture and OS specific features. Any encountered extension |
| 4730 | is an error. */ |
| 4731 | |
| 4732 | /* Go straight by the gABI, check all the parts in turn. */ |
| 4733 | check_elf_header (ebl, ehdr, size); |
| 4734 | |
| 4735 | /* Check the program header. */ |
| 4736 | check_program_header (ebl, ehdr); |
| 4737 | |
| 4738 | /* Next the section headers. It is OK if there are no section |
| 4739 | headers at all. */ |
| 4740 | check_sections (ebl, ehdr); |
| 4741 | |
| 4742 | /* Check the exception handling data, if it exists. */ |
| 4743 | if (pt_gnu_eh_frame_pndx != 0 || eh_frame_hdr_scnndx != 0 |
| 4744 | || eh_frame_scnndx != 0 || gcc_except_table_scnndx != 0) |
| 4745 | check_exception_data (ebl, ehdr); |
| 4746 | |
| 4747 | /* Report if no relocation section needed the text relocation flag. */ |
| 4748 | if (textrel && !needed_textrel) |
| 4749 | ERROR (gettext ("text relocation flag set but not needed\n")); |
| 4750 | |
| 4751 | /* Free the resources. */ |
| 4752 | ebl_closebackend (ebl); |
| 4753 | } |
| 4754 | |
| 4755 | |
| 4756 | #include "debugpred.h" |