static int elf_read_phdr(const char *buf, size_t len, struct elf_info *elf_info, int idx) { /* Override the const in proghdrs, we are the ones doing the loading. */ struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx]; const char *pbuf; struct elf_phdr *buf_phdr; pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr)); buf_phdr = (struct elf_phdr *) pbuf; phdr->p_type = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type); phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset); phdr->p_paddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr); phdr->p_vaddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr); phdr->p_flags = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags); /* * The following fields have a type equivalent to Elf_Addr * both in 32 bit and 64 bit ELF. */ phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz); phdr->p_memsz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz); phdr->p_align = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align); return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC; }
static int build_mem_elf64_phdr(const char *buf, off_t len, struct mem_ehdr *ehdr, int idx) { struct mem_phdr *phdr; const char *pbuf; Elf64_Phdr lphdr; pbuf = buf + ehdr->e_phoff + (idx * sizeof(lphdr)); phdr = &ehdr->e_phdr[idx]; memcpy(&lphdr, pbuf, sizeof(lphdr)); if ( (elf64_to_cpu(ehdr, lphdr.p_filesz) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_memsz) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_offset) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_paddr) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_vaddr) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_align) > UINT64_MAX)) { fprintf(stderr, "Program segment size out of range\n"); return -1; } phdr->p_type = elf32_to_cpu(ehdr, lphdr.p_type); phdr->p_paddr = elf64_to_cpu(ehdr, lphdr.p_paddr); phdr->p_vaddr = elf64_to_cpu(ehdr, lphdr.p_vaddr); phdr->p_filesz = elf64_to_cpu(ehdr, lphdr.p_filesz); phdr->p_memsz = elf64_to_cpu(ehdr, lphdr.p_memsz); phdr->p_offset = elf64_to_cpu(ehdr, lphdr.p_offset); phdr->p_flags = elf32_to_cpu(ehdr, lphdr.p_flags); phdr->p_align = elf64_to_cpu(ehdr, lphdr.p_align); return 0; }
static int elf_read_shdr(const char *buf, size_t len, struct elf_info *elf_info, int idx) { struct elf_shdr *shdr = &elf_info->sechdrs[idx]; const struct elfhdr *ehdr = elf_info->ehdr; const char *sbuf; struct elf_shdr *buf_shdr; sbuf = buf + ehdr->e_shoff + idx * sizeof(*buf_shdr); buf_shdr = (struct elf_shdr *) sbuf; shdr->sh_name = elf32_to_cpu(ehdr, buf_shdr->sh_name); shdr->sh_type = elf32_to_cpu(ehdr, buf_shdr->sh_type); shdr->sh_addr = elf_addr_to_cpu(ehdr, buf_shdr->sh_addr); shdr->sh_offset = elf_addr_to_cpu(ehdr, buf_shdr->sh_offset); shdr->sh_link = elf32_to_cpu(ehdr, buf_shdr->sh_link); shdr->sh_info = elf32_to_cpu(ehdr, buf_shdr->sh_info); /* * The following fields have a type equivalent to Elf_Addr * both in 32 bit and 64 bit ELF. */ shdr->sh_flags = elf_addr_to_cpu(ehdr, buf_shdr->sh_flags); shdr->sh_size = elf_addr_to_cpu(ehdr, buf_shdr->sh_size); shdr->sh_addralign = elf_addr_to_cpu(ehdr, buf_shdr->sh_addralign); shdr->sh_entsize = elf_addr_to_cpu(ehdr, buf_shdr->sh_entsize); return elf_is_shdr_sane(shdr, len) ? 0 : -ENOEXEC; }
static struct mem_sym elf_sym(struct mem_ehdr *ehdr, const unsigned char *ptr) { struct mem_sym sym = { }; if (ehdr->ei_class == ELFCLASS32) { Elf32_Sym lsym; memcpy(&lsym, ptr, sizeof(lsym)); sym.st_name = elf32_to_cpu(ehdr, lsym.st_name); sym.st_value = elf32_to_cpu(ehdr, lsym.st_value); sym.st_size = elf32_to_cpu(ehdr, lsym.st_size); sym.st_info = lsym.st_info; sym.st_other = lsym.st_other; sym.st_shndx = elf16_to_cpu(ehdr, lsym.st_shndx); } else if (ehdr->ei_class == ELFCLASS64) { Elf64_Sym lsym; memcpy(&lsym, ptr, sizeof(lsym)); sym.st_name = elf32_to_cpu(ehdr, lsym.st_name); sym.st_value = elf64_to_cpu(ehdr, lsym.st_value); sym.st_size = elf64_to_cpu(ehdr, lsym.st_size); sym.st_info = lsym.st_info; sym.st_other = lsym.st_other; sym.st_shndx = elf16_to_cpu(ehdr, lsym.st_shndx); } else { die("Bad elf class"); } return sym; }
static void read_nhdr(const struct mem_ehdr *ehdr, ElfNN_Nhdr *hdr, const unsigned char *note) { memcpy(hdr, note, sizeof(*hdr)); hdr->n_namesz = elf32_to_cpu(ehdr, hdr->n_namesz); hdr->n_descsz = elf32_to_cpu(ehdr, hdr->n_descsz); hdr->n_type = elf32_to_cpu(ehdr, hdr->n_type); }
static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr) { struct elfhdr *buf_ehdr; if (len < sizeof(*buf_ehdr)) { pr_debug("Buffer is too small to hold ELF header.\n"); return -ENOEXEC; } memset(ehdr, 0, sizeof(*ehdr)); memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident)); if (!elf_is_elf_file(ehdr)) { pr_debug("No ELF header magic.\n"); return -ENOEXEC; } if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) { pr_debug("Not a supported ELF class.\n"); return -1; } else if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB && ehdr->e_ident[EI_DATA] != ELFDATA2MSB) { pr_debug("Not a supported ELF data format.\n"); return -ENOEXEC; } buf_ehdr = (struct elfhdr *) buf; if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) { pr_debug("Bad ELF header size.\n"); return -ENOEXEC; } ehdr->e_type = elf16_to_cpu(ehdr, buf_ehdr->e_type); ehdr->e_machine = elf16_to_cpu(ehdr, buf_ehdr->e_machine); ehdr->e_version = elf32_to_cpu(ehdr, buf_ehdr->e_version); ehdr->e_entry = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry); ehdr->e_phoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff); ehdr->e_shoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff); ehdr->e_flags = elf32_to_cpu(ehdr, buf_ehdr->e_flags); ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize); ehdr->e_phnum = elf16_to_cpu(ehdr, buf_ehdr->e_phnum); ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize); ehdr->e_shnum = elf16_to_cpu(ehdr, buf_ehdr->e_shnum); ehdr->e_shstrndx = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx); return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC; }
static struct mem_rela elf_rel(struct mem_ehdr *ehdr, const unsigned char *ptr) { struct mem_rela rela = { }; if (ehdr->ei_class == ELFCLASS32) { Elf32_Rel lrel; memcpy(&lrel, ptr, sizeof(lrel)); rela.r_offset = elf32_to_cpu(ehdr, lrel.r_offset); rela.r_sym = ELF32_R_SYM(elf32_to_cpu(ehdr, lrel.r_info)); rela.r_type = ELF32_R_TYPE(elf32_to_cpu(ehdr, lrel.r_info)); rela.r_addend = 0; } else if (ehdr->ei_class == ELFCLASS64) { Elf64_Rel lrel; memcpy(&lrel, ptr, sizeof(lrel)); rela.r_offset = elf64_to_cpu(ehdr, lrel.r_offset); rela.r_sym = ELF64_R_SYM(elf64_to_cpu(ehdr, lrel.r_info)); rela.r_type = ELF64_R_TYPE(elf64_to_cpu(ehdr, lrel.r_info)); rela.r_addend = 0; } else { die("Bad elf class"); } return rela; }
static int build_mem_elf32_ehdr(const char *buf, off_t len, struct mem_ehdr *ehdr) { Elf32_Ehdr lehdr; if (len < sizeof(lehdr)) { /* Buffer is to small to be an elf executable */ if (probe_debug) { fprintf(stderr, "Buffer is to small to hold ELF header\n"); } return -1; } memcpy(&lehdr, buf, sizeof(lehdr)); if (elf16_to_cpu(ehdr, lehdr.e_ehsize) != sizeof(Elf32_Ehdr)) { /* Invalid Elf header size */ if (probe_debug) { fprintf(stderr, "Bad ELF header size\n"); } return -1; } if (elf32_to_cpu(ehdr, lehdr.e_entry) > UINT32_MAX) { /* entry is to large */ if (probe_debug) { fprintf(stderr, "ELF e_entry to large\n"); } return -1; } if (elf32_to_cpu(ehdr, lehdr.e_phoff) > UINT32_MAX) { /* phoff is to large */ if (probe_debug) { fprintf(stderr, "ELF e_phoff to large\n"); } return -1; } if (elf32_to_cpu(ehdr, lehdr.e_shoff) > UINT32_MAX) { /* shoff is to large */ if (probe_debug) { fprintf(stderr, "ELF e_shoff to large\n"); } return -1; } ehdr->e_type = elf16_to_cpu(ehdr, lehdr.e_type); ehdr->e_machine = elf16_to_cpu(ehdr, lehdr.e_machine); ehdr->e_version = elf32_to_cpu(ehdr, lehdr.e_version); ehdr->e_entry = elf32_to_cpu(ehdr, lehdr.e_entry); ehdr->e_phoff = elf32_to_cpu(ehdr, lehdr.e_phoff); ehdr->e_shoff = elf32_to_cpu(ehdr, lehdr.e_shoff); ehdr->e_flags = elf32_to_cpu(ehdr, lehdr.e_flags); ehdr->e_phnum = elf16_to_cpu(ehdr, lehdr.e_phnum); ehdr->e_shnum = elf16_to_cpu(ehdr, lehdr.e_shnum); ehdr->e_shstrndx = elf16_to_cpu(ehdr, lehdr.e_shstrndx); if ((ehdr->e_phnum > 0) && (elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf32_Phdr))) { /* Invalid program header size */ if (probe_debug) { fprintf(stderr, "ELF bad program header size\n"); } return -1; } if ((ehdr->e_shnum > 0) && (elf16_to_cpu(ehdr, lehdr.e_shentsize) != sizeof(Elf32_Shdr))) { /* Invalid section header size */ if (probe_debug) { fprintf(stderr, "ELF bad section header size\n"); } return -1; } return 0; }
static int build_mem_elf64_shdr(const char *buf, off_t len, struct mem_ehdr *ehdr, int idx) { struct mem_shdr *shdr; const char *sbuf; int size_ok; Elf64_Shdr lshdr; sbuf = buf + ehdr->e_shoff + (idx * sizeof(lshdr)); shdr = &ehdr->e_shdr[idx]; memcpy(&lshdr, sbuf, sizeof(lshdr)); if ( (elf64_to_cpu(ehdr, lshdr.sh_flags) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_addr) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_offset) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_size) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_addralign) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_entsize) > UINT64_MAX)) { fprintf(stderr, "Program section size out of range\n"); return -1; } shdr->sh_name = elf32_to_cpu(ehdr, lshdr.sh_name); shdr->sh_type = elf32_to_cpu(ehdr, lshdr.sh_type); shdr->sh_flags = elf64_to_cpu(ehdr, lshdr.sh_flags); shdr->sh_addr = elf64_to_cpu(ehdr, lshdr.sh_addr); shdr->sh_offset = elf64_to_cpu(ehdr, lshdr.sh_offset); shdr->sh_size = elf64_to_cpu(ehdr, lshdr.sh_size); shdr->sh_link = elf32_to_cpu(ehdr, lshdr.sh_link); shdr->sh_info = elf32_to_cpu(ehdr, lshdr.sh_info); shdr->sh_addralign = elf64_to_cpu(ehdr, lshdr.sh_addralign); shdr->sh_entsize = elf64_to_cpu(ehdr, lshdr.sh_entsize); /* Now verify sh_entsize */ size_ok = 0; switch(shdr->sh_type) { case SHT_SYMTAB: size_ok = shdr->sh_entsize == sizeof(Elf64_Sym); break; case SHT_RELA: size_ok = shdr->sh_entsize == sizeof(Elf64_Rela); break; case SHT_DYNAMIC: size_ok = shdr->sh_entsize == sizeof(Elf64_Dyn); break; case SHT_REL: size_ok = shdr->sh_entsize == sizeof(Elf64_Rel); break; case SHT_NOTE: case SHT_NULL: case SHT_PROGBITS: case SHT_HASH: case SHT_NOBITS: default: /* This is a section whose entsize requirements * I don't care about. If I don't know about * the section I can't care about it's entsize * requirements. */ size_ok = 1; break; } if (!size_ok) { fprintf(stderr, "Bad section header(%x) entsize: %ld\n", shdr->sh_type, shdr->sh_entsize); return -1; } return 0; }