#define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr
#define grub_elfXX_get_shnum grub_elf32_get_shnum
#define grub_elfXX_get_shstrndx grub_elf32_get_shstrndx
+#define grub_elfXX_get_phnum grub_elf32_get_phnum
#include "elfXX.c"
#undef grub_elfXX_check_endianess_and_bswap_ehdr
#undef grub_elfXX_get_shnum
#undef grub_elfXX_get_shstrndx
+#undef grub_elfXX_get_phnum
\f
/* 64-bit */
#define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr
#define grub_elfXX_get_shnum grub_elf64_get_shnum
#define grub_elfXX_get_shstrndx grub_elf64_get_shstrndx
+#define grub_elfXX_get_phnum grub_elf64_get_phnum
#include "elfXX.c"
}
return GRUB_ERR_NONE;
}
+
+grub_err_t
+grub_elfXX_get_phnum (ElfXX_Ehdr *e, ElfXX_Word *phnum)
+{
+ ElfXX_Shdr *s;
+
+ if (phnum == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for phnum"));
+
+ /* Set *phnum to 0 so that phnum doesn't return junk on error */
+ *phnum = 0;
+
+ if (e == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer passed for elf header"));
+
+ *phnum = e->e_phnum;
+ if (*phnum == PN_XNUM)
+ {
+ if (e->e_shoff == 0)
+ return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid section header table offset in e_shoff"));
+
+ s = (ElfXX_Shdr *) ((grub_uint8_t *) e + e->e_shoff);
+ *phnum = s->sh_info;
+ if (*phnum < PN_XNUM)
+ return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in sh_info: %d"), *phnum);
+ }
+ else
+ {
+ if (*phnum >= PN_XNUM)
+ return grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid number of program header table entries in e_phnum: %d"), *phnum);
+ }
+
+ return GRUB_ERR_NONE;
+}
Elf_Ehdr e;
Elf_Shdr *s, *shdr = NULL;
Elf_Shnum shnum;
+ Elf_Word phnum;
grub_addr_t curload, module;
grub_err_t err;
grub_size_t chunk_size = 0;
if (err != GRUB_ERR_NONE)
goto out;
+ err = grub_elf_get_phnum (&e, &phnum);
+ if (err != GRUB_ERR_NONE)
+ goto out;
+
for (s = shdr; s < (Elf_Shdr *) ((grub_uint8_t *) shdr + shnum * e.e_shentsize);
s = (Elf_Shdr *) ((grub_uint8_t *) s + e.e_shentsize))
{
if (chunk_size < sizeof (e))
chunk_size = sizeof (e);
- chunk_size += (grub_uint32_t) e.e_phnum * e.e_phentsize;
+ chunk_size += (grub_size_t) phnum * e.e_phentsize;
chunk_size += (grub_size_t) shnum * e.e_shentsize;
{
curload += (grub_addr_t) shnum * e.e_shentsize;
load (file, argv[0], (grub_uint8_t *) chunk_src + curload - *kern_end, e.e_phoff,
- (grub_uint32_t) e.e_phnum * e.e_phentsize);
+ (grub_size_t) phnum * e.e_phentsize);
e.e_phoff = curload - module;
- curload += (grub_uint32_t) e.e_phnum * e.e_phentsize;
+ curload += (grub_addr_t) phnum * e.e_phentsize;
*kern_end = curload;
# define Elf_Shnum Elf32_Shnum
# define grub_multiboot_elf_get_shnum grub_elf32_get_shnum
# define grub_multiboot_elf_get_shstrndx grub_elf32_get_shstrndx
+# define grub_multiboot_elf_get_phnum grub_elf32_get_phnum
#elif defined(MULTIBOOT_LOAD_ELF64)
# define XX 64
# define E_MACHINE MULTIBOOT_ELF64_MACHINE
# define Elf_Shnum Elf64_Shnum
# define grub_multiboot_elf_get_shnum grub_elf64_get_shnum
# define grub_multiboot_elf_get_shstrndx grub_elf64_get_shstrndx
+# define grub_multiboot_elf_get_phnum grub_elf64_get_phnum
#else
#error "I'm confused"
#endif
grub_relocator_chunk_t ch;
grub_uint32_t load_offset = 0, load_size;
Elf_Shnum shnum;
- Elf_Word shstrndx;
+ Elf_Word shstrndx, phnum;
unsigned int i;
void *source = NULL;
if (err != GRUB_ERR_NONE)
return err;
+ err = grub_multiboot_elf_get_phnum (ehdr, &phnum);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
/* FIXME: Should we support program headers at strange locations? */
- if (ehdr->e_phoff + (grub_uint32_t) ehdr->e_phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
+ if (ehdr->e_phoff + phnum * ehdr->e_phentsize > MULTIBOOT_SEARCH)
return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset");
phdr_base = (char *) mld->buffer + ehdr->e_phoff;
mld->link_base_addr = ~0;
/* Calculate lowest and highest load address. */
- for (i = 0; i < ehdr->e_phnum; i++)
+ for (i = 0; i < phnum; i++)
if (phdr(i)->p_type == PT_LOAD)
{
mld->link_base_addr = grub_min (mld->link_base_addr, phdr(i)->p_paddr);
mld->link_base_addr, mld->load_base_addr);
/* Load every loadable segment in memory. */
- for (i = 0; i < ehdr->e_phnum; i++)
+ for (i = 0; i < phnum; i++)
{
if (phdr(i)->p_type == PT_LOAD)
{
}
}
- for (i = 0; i < ehdr->e_phnum; i++)
+ for (i = 0; i < phnum; i++)
if (phdr(i)->p_vaddr <= ehdr->e_entry
&& phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry)
{
break;
}
- if (i == ehdr->e_phnum)
+ if (i == phnum)
return grub_error (GRUB_ERR_BAD_OS, "entry point isn't in a segment");
#if defined (__i386__) || defined (__x86_64__)
#undef Elf_Shnum
#undef grub_multiboot_elf_get_shnum
#undef grub_multiboot_elf_get_shstrndx
+#undef grub_multiboot_elf_get_phnum
#define PT_HIOS 0x6fffffff /* End of OS-specific */
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
#define PT_HIPROC 0x7fffffff /* End of processor-specific */
+#define PN_XNUM 0xffff
/* Legal values for p_flags (segment flags). */
extern grub_err_t grub_elf32_get_shnum (Elf32_Ehdr *e, Elf32_Shnum *shnum);
extern grub_err_t grub_elf32_get_shstrndx (Elf32_Ehdr *e, Elf32_Word *shstrndx);
+extern grub_err_t grub_elf32_get_phnum (Elf32_Ehdr *e, Elf32_Word *phnum);
extern grub_err_t grub_elf64_get_shnum (Elf64_Ehdr *e, Elf64_Shnum *shnum);
extern grub_err_t grub_elf64_get_shstrndx (Elf64_Ehdr *e, Elf64_Word *shstrndx);
+extern grub_err_t grub_elf64_get_phnum (Elf64_Ehdr *e, Elf64_Word *phnum);
#ifdef GRUB_TARGET_WORDSIZE
#if GRUB_TARGET_WORDSIZE == 32
#define grub_elf_get_shnum grub_elf32_get_shnum
#define grub_elf_get_shstrndx grub_elf32_get_shstrndx
+#define grub_elf_get_phnum grub_elf32_get_phnum
#elif GRUB_TARGET_WORDSIZE == 64
#define grub_elf_get_shnum grub_elf64_get_shnum
#define grub_elf_get_shstrndx grub_elf64_get_shstrndx
+#define grub_elf_get_phnum grub_elf64_get_phnum
#endif /* GRUB_TARGET_WORDSIZE == 64 */
#endif