mirror of
https://git.proxmox.com/git/grub2
synced 2025-10-29 19:23:49 +00:00
191 lines
6.4 KiB
Diff
191 lines
6.4 KiB
Diff
From 4a42ac8d567ce0a74687f2da6afb9e88f6d4099d Mon Sep 17 00:00:00 2001
|
||
From: Tomohiro B Berry <tbberry@us.ibm.com>
|
||
Date: Tue, 14 Jan 2014 17:43:25 +0000
|
||
Subject: Add bi-endian support to ELF parser
|
||
|
||
This patch adds bi-endian support for both 32-bit and 64-bit elf files.
|
||
|
||
It compares the native endianness to the endianness of the elf file, and
|
||
swaps the header bytes if necessary. This will allow, for example,
|
||
32-bit Big Endian grub to load a 64-bit Little Endian kernel.
|
||
|
||
Origin: other, https://lists.gnu.org/archive/html/grub-devel/2014-01/msg00039.html
|
||
|
||
Patch-Name: elf_bi_endian.patch
|
||
---
|
||
grub-core/kern/elf.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++--
|
||
grub-core/kern/elfXX.c | 43 +++++++++++++++++++++++++++++++++++++++
|
||
include/grub/elf.h | 7 +++++++
|
||
3 files changed, 103 insertions(+), 2 deletions(-)
|
||
|
||
diff --git a/grub-core/kern/elf.c b/grub-core/kern/elf.c
|
||
index 5f99c43..9a3cc71 100644
|
||
--- a/grub-core/kern/elf.c
|
||
+++ b/grub-core/kern/elf.c
|
||
@@ -28,20 +28,45 @@
|
||
|
||
GRUB_MOD_LICENSE ("GPLv3+");
|
||
|
||
+void grub_elf32_byteswap_header (grub_elf_t elf);
|
||
+void grub_elf64_byteswap_header (grub_elf_t elf);
|
||
+grub_err_t grub_elf32_check_version (grub_elf_t elf);
|
||
+grub_err_t grub_elf64_check_version (grub_elf_t elf);
|
||
+
|
||
/* Check if EHDR is a valid ELF header. */
|
||
static grub_err_t
|
||
grub_elf_check_header (grub_elf_t elf)
|
||
{
|
||
+ /* e_ident is the same for both 64-bit and 32-bit so just load into a 32-bit struct for now */
|
||
Elf32_Ehdr *e = &elf->ehdr.ehdr32;
|
||
|
||
+ /* check if it is an ELF image at all */
|
||
if (e->e_ident[EI_MAG0] != ELFMAG0
|
||
|| e->e_ident[EI_MAG1] != ELFMAG1
|
||
|| e->e_ident[EI_MAG2] != ELFMAG2
|
||
|| e->e_ident[EI_MAG3] != ELFMAG3
|
||
- || e->e_ident[EI_VERSION] != EV_CURRENT
|
||
- || e->e_version != EV_CURRENT)
|
||
+ || e->e_ident[EI_VERSION] != EV_CURRENT)
|
||
return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
|
||
|
||
+ switch (e->e_ident[EI_CLASS])
|
||
+ {
|
||
+ case ELFCLASS32:
|
||
+ if (e->e_ident[EI_DATA] != ELFDATA_NATIVE)
|
||
+ grub_elf32_byteswap_header (elf);
|
||
+ if (grub_elf32_check_version (elf) != GRUB_ERR_NONE)
|
||
+ return grub_errno;
|
||
+ break;
|
||
+ case ELFCLASS64:
|
||
+ if (e->e_ident[EI_DATA] != ELFDATA_NATIVE)
|
||
+ grub_elf64_byteswap_header (elf);
|
||
+ if (grub_elf64_check_version (elf) != GRUB_ERR_NONE)
|
||
+ return grub_errno;
|
||
+ break;
|
||
+ default:
|
||
+ return grub_error (GRUB_ERR_BAD_OS, N_("unrecognized ELF class"));
|
||
+ break;
|
||
+ }
|
||
+
|
||
return GRUB_ERR_NONE;
|
||
}
|
||
|
||
@@ -127,7 +152,16 @@ grub_elf_open (const char *name)
|
||
#define grub_elf_is_elfXX grub_elf_is_elf32
|
||
#define grub_elfXX_load_phdrs grub_elf32_load_phdrs
|
||
#define ElfXX_Phdr Elf32_Phdr
|
||
+#define ElfXX_Ehdr Elf32_Ehdr
|
||
#define grub_uintXX_t grub_uint32_t
|
||
+/* for phdr/ehdr byte swaps */
|
||
+#define byte_swap_halfXX grub_swap_bytes16
|
||
+#define byte_swap_wordXX grub_swap_bytes32
|
||
+#define byte_swap_addrXX grub_swap_bytes32
|
||
+#define byte_swap_offXX grub_swap_bytes32
|
||
+#define byte_swap_XwordXX byte_swap_wordXX /* the 64-bit phdr uses Xwords and the 32-bit uses words */
|
||
+#define grub_elfXX_byteswap_header grub_elf32_byteswap_header
|
||
+#define grub_elfXX_check_version grub_elf32_check_version
|
||
|
||
#include "elfXX.c"
|
||
|
||
@@ -140,7 +174,15 @@ grub_elf_open (const char *name)
|
||
#undef grub_elf_is_elfXX
|
||
#undef grub_elfXX_load_phdrs
|
||
#undef ElfXX_Phdr
|
||
+#undef ElfXX_Ehdr
|
||
#undef grub_uintXX_t
|
||
+#undef byte_swap_halfXX
|
||
+#undef byte_swap_wordXX
|
||
+#undef byte_swap_addrXX
|
||
+#undef byte_swap_offXX
|
||
+#undef byte_swap_XwordXX
|
||
+#undef grub_elfXX_byteswap_header
|
||
+#undef grub_elfXX_check_version
|
||
|
||
|
||
/* 64-bit */
|
||
@@ -153,6 +195,15 @@ grub_elf_open (const char *name)
|
||
#define grub_elf_is_elfXX grub_elf_is_elf64
|
||
#define grub_elfXX_load_phdrs grub_elf64_load_phdrs
|
||
#define ElfXX_Phdr Elf64_Phdr
|
||
+#define ElfXX_Ehdr Elf64_Ehdr
|
||
#define grub_uintXX_t grub_uint64_t
|
||
+/* for phdr/ehdr byte swaps */
|
||
+#define byte_swap_halfXX grub_swap_bytes16
|
||
+#define byte_swap_wordXX grub_swap_bytes32
|
||
+#define byte_swap_addrXX grub_swap_bytes64
|
||
+#define byte_swap_offXX grub_swap_bytes64
|
||
+#define byte_swap_XwordXX grub_swap_bytes64
|
||
+#define grub_elfXX_byteswap_header grub_elf64_byteswap_header
|
||
+#define grub_elfXX_check_version grub_elf64_check_version
|
||
|
||
#include "elfXX.c"
|
||
diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c
|
||
index 1d09971..639cda6 100644
|
||
--- a/grub-core/kern/elfXX.c
|
||
+++ b/grub-core/kern/elfXX.c
|
||
@@ -154,3 +154,46 @@ grub_elfXX_load (grub_elf_t elf, const char *filename,
|
||
|
||
return grub_errno;
|
||
}
|
||
+
|
||
+void
|
||
+grub_elfXX_byteswap_header (grub_elf_t elf)
|
||
+{
|
||
+ ElfXX_Ehdr *e = &(elf->ehdr.ehdrXX);
|
||
+ ElfXX_Phdr *phdr;
|
||
+
|
||
+ e->e_type = byte_swap_halfXX (e->e_type);
|
||
+ e->e_machine = byte_swap_halfXX (e->e_machine);
|
||
+ e->e_version = byte_swap_wordXX (e->e_version);
|
||
+ e->e_entry = byte_swap_addrXX (e->e_entry);
|
||
+ e->e_phoff = byte_swap_offXX (e->e_phoff);
|
||
+ e->e_shoff = byte_swap_offXX (e->e_shoff);
|
||
+ e->e_flags = byte_swap_wordXX (e->e_flags);
|
||
+ e->e_ehsize = byte_swap_halfXX (e->e_ehsize);
|
||
+ e->e_phentsize = byte_swap_halfXX (e->e_phentsize);
|
||
+ e->e_phnum = byte_swap_halfXX (e->e_phnum);
|
||
+ e->e_shentsize = byte_swap_halfXX (e->e_shentsize);
|
||
+ e->e_shnum = byte_swap_halfXX (e->e_shnum);
|
||
+ e->e_shstrndx = byte_swap_halfXX (e->e_shstrndx);
|
||
+
|
||
+ FOR_ELFXX_PHDRS (elf,phdr)
|
||
+ {
|
||
+ phdr->p_type = byte_swap_wordXX (phdr->p_type);
|
||
+ phdr->p_flags = byte_swap_wordXX (phdr->p_flags);
|
||
+ phdr->p_offset = byte_swap_offXX (phdr->p_offset);
|
||
+ phdr->p_vaddr = byte_swap_addrXX (phdr->p_vaddr);
|
||
+ phdr->p_paddr = byte_swap_addrXX (phdr->p_paddr);
|
||
+ phdr->p_filesz = byte_swap_XwordXX (phdr->p_filesz);
|
||
+ phdr->p_memsz = byte_swap_XwordXX (phdr->p_memsz);
|
||
+ phdr->p_align = byte_swap_XwordXX (phdr->p_align);
|
||
+ }
|
||
+
|
||
+}
|
||
+
|
||
+grub_err_t
|
||
+grub_elfXX_check_version (grub_elf_t elf)
|
||
+{
|
||
+ if (elf->ehdr.ehdrXX.e_version != EV_CURRENT)
|
||
+ return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
|
||
+
|
||
+ return GRUB_ERR_NONE;
|
||
+}
|
||
diff --git a/include/grub/elf.h b/include/grub/elf.h
|
||
index caa7963..ca6e436 100644
|
||
--- a/include/grub/elf.h
|
||
+++ b/include/grub/elf.h
|
||
@@ -56,6 +56,13 @@ typedef grub_uint16_t Elf64_Section;
|
||
typedef Elf32_Half Elf32_Versym;
|
||
typedef Elf64_Half Elf64_Versym;
|
||
|
||
+/* Define the native endianness */
|
||
+
|
||
+#ifdef GRUB_CPU_WORDS_BIGENDIAN
|
||
+#define ELFDATA_NATIVE ELFDATA2MSB
|
||
+#else
|
||
+#define ELFDATA_NATIVE ELFDATA2LSB
|
||
+#endif
|
||
|
||
/* The ELF file header. This appears at the start of every ELF file. */
|
||
|