summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibELF
diff options
context:
space:
mode:
authorGunnar Beutner <gbeutner@serenityos.org>2021-06-28 17:24:08 +0200
committerAndreas Kling <kling@serenityos.org>2021-06-28 22:29:28 +0200
commit158355e0d773d1121286bf7a51575b554be98806 (patch)
treed2aa14921fe926236e8d2e58dfe316a0f6e23bff /Userland/Libraries/LibELF
parente35b0605013163ea2f3425ec4ed4489e64d03280 (diff)
downloadserenity-158355e0d773d1121286bf7a51575b554be98806.zip
Kernel+LibELF: Add support for validating and loading ELF64 executables
Diffstat (limited to 'Userland/Libraries/LibELF')
-rw-r--r--Userland/Libraries/LibELF/DynamicLoader.cpp4
-rw-r--r--Userland/Libraries/LibELF/DynamicLoader.h4
-rw-r--r--Userland/Libraries/LibELF/Image.cpp22
-rw-r--r--Userland/Libraries/LibELF/Image.h20
-rw-r--r--Userland/Libraries/LibELF/Validation.cpp53
-rw-r--r--Userland/Libraries/LibELF/Validation.h4
6 files changed, 65 insertions, 42 deletions
diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp
index 6321954aa1..8788679575 100644
--- a/Userland/Libraries/LibELF/DynamicLoader.cpp
+++ b/Userland/Libraries/LibELF/DynamicLoader.cpp
@@ -45,7 +45,7 @@ Result<NonnullRefPtr<DynamicLoader>, DlErrorMessage> DynamicLoader::try_create(i
VERIFY(stat.st_size >= 0);
auto size = static_cast<size_t>(stat.st_size);
- if (size < sizeof(Elf32_Ehdr))
+ if (size < sizeof(ElfW(Ehdr)))
return DlErrorMessage { String::formatted("File {} has invalid ELF header", filename) };
String file_mmap_name = String::formatted("ELF_DYN: {}", filename);
@@ -117,7 +117,7 @@ bool DynamicLoader::validate()
if (!m_elf_image.is_valid())
return false;
- auto* elf_header = (Elf32_Ehdr*)m_file_data;
+ auto* elf_header = (ElfW(Ehdr)*)m_file_data;
if (!validate_elf_header(*elf_header, m_file_size))
return false;
if (!validate_program_headers(*elf_header, m_file_size, (u8*)m_file_data, m_file_size, &m_program_interpreter))
diff --git a/Userland/Libraries/LibELF/DynamicLoader.h b/Userland/Libraries/LibELF/DynamicLoader.h
index 64c6e5a821..a3850723b8 100644
--- a/Userland/Libraries/LibELF/DynamicLoader.h
+++ b/Userland/Libraries/LibELF/DynamicLoader.h
@@ -85,7 +85,7 @@ private:
class ProgramHeaderRegion {
public:
- void set_program_header(const Elf32_Phdr& header) { m_program_header = header; }
+ void set_program_header(const ElfW(Phdr) & header) { m_program_header = header; }
// Information from ELF Program header
u32 type() const { return m_program_header.p_type; }
@@ -104,7 +104,7 @@ private:
bool is_relro() const { return type() == PT_GNU_RELRO; }
private:
- Elf32_Phdr m_program_header; // Explicitly a copy of the PHDR in the image
+ ElfW(Phdr) m_program_header; // Explicitly a copy of the PHDR in the image
};
const DynamicObject& dynamic_object() const;
diff --git a/Userland/Libraries/LibELF/Image.cpp b/Userland/Libraries/LibELF/Image.cpp
index c0f5399918..393738a764 100644
--- a/Userland/Libraries/LibELF/Image.cpp
+++ b/Userland/Libraries/LibELF/Image.cpp
@@ -35,7 +35,7 @@ Image::~Image()
}
#if ELF_IMAGE_DEBUG
-static const char* object_file_type_to_string(Elf32_Half type)
+static const char* object_file_type_to_string(ElfW(Half) type)
{
switch (type) {
case ET_NONE:
@@ -139,7 +139,7 @@ unsigned Image::program_header_count() const
bool Image::parse()
{
- if (m_size < sizeof(Elf32_Ehdr) || !validate_elf_header(header(), m_size, m_verbose_logging)) {
+ if (m_size < sizeof(ElfW(Ehdr)) || !validate_elf_header(header(), m_size, m_verbose_logging)) {
if (m_verbose_logging)
dbgln("ELF::Image::parse(): ELF Header not valid");
m_valid = false;
@@ -209,31 +209,31 @@ const char* Image::raw_data(unsigned offset) const
return reinterpret_cast<const char*>(m_buffer) + offset;
}
-const Elf32_Ehdr& Image::header() const
+const ElfW(Ehdr) & Image::header() const
{
- VERIFY(m_size >= sizeof(Elf32_Ehdr));
- return *reinterpret_cast<const Elf32_Ehdr*>(raw_data(0));
+ VERIFY(m_size >= sizeof(ElfW(Ehdr)));
+ return *reinterpret_cast<const ElfW(Ehdr)*>(raw_data(0));
}
-const Elf32_Phdr& Image::program_header_internal(unsigned index) const
+const ElfW(Phdr) & Image::program_header_internal(unsigned index) const
{
VERIFY(m_valid);
VERIFY(index < header().e_phnum);
- return *reinterpret_cast<const Elf32_Phdr*>(raw_data(header().e_phoff + (index * sizeof(Elf32_Phdr))));
+ return *reinterpret_cast<const ElfW(Phdr)*>(raw_data(header().e_phoff + (index * sizeof(ElfW(Phdr)))));
}
-const Elf32_Shdr& Image::section_header(unsigned index) const
+const ElfW(Shdr) & Image::section_header(unsigned index) const
{
VERIFY(m_valid);
VERIFY(index < header().e_shnum);
- return *reinterpret_cast<const Elf32_Shdr*>(raw_data(header().e_shoff + (index * header().e_shentsize)));
+ return *reinterpret_cast<const ElfW(Shdr)*>(raw_data(header().e_shoff + (index * header().e_shentsize)));
}
Image::Symbol Image::symbol(unsigned index) const
{
VERIFY(m_valid);
VERIFY(index < symbol_count());
- auto* raw_syms = reinterpret_cast<const Elf32_Sym*>(raw_data(section(m_symbol_table_section_index).offset()));
+ auto* raw_syms = reinterpret_cast<const ElfW(Sym)*>(raw_data(section(m_symbol_table_section_index).offset()));
return Symbol(*this, index, raw_syms[index]);
}
@@ -254,7 +254,7 @@ Image::ProgramHeader Image::program_header(unsigned index) const
Image::Relocation Image::RelocationSection::relocation(unsigned index) const
{
VERIFY(index < relocation_count());
- auto* rels = reinterpret_cast<const Elf32_Rel*>(m_image.raw_data(offset()));
+ auto* rels = reinterpret_cast<const ElfW(Rel)*>(m_image.raw_data(offset()));
return Relocation(m_image, rels[index]);
}
diff --git a/Userland/Libraries/LibELF/Image.h b/Userland/Libraries/LibELF/Image.h
index 3f7f369e8e..70ec1a76fd 100644
--- a/Userland/Libraries/LibELF/Image.h
+++ b/Userland/Libraries/LibELF/Image.h
@@ -40,7 +40,7 @@ public:
class Symbol {
public:
- Symbol(const Image& image, unsigned index, const Elf32_Sym& sym)
+ Symbol(const Image& image, unsigned index, const ElfW(Sym) & sym)
: m_image(image)
, m_sym(sym)
, m_index(index)
@@ -62,7 +62,7 @@ public:
private:
const Image& m_image;
- const Elf32_Sym& m_sym;
+ const ElfW(Sym) & m_sym;
const unsigned m_index;
};
@@ -88,11 +88,11 @@ public:
bool is_writable() const { return flags() & PF_W; }
bool is_executable() const { return flags() & PF_X; }
const char* raw_data() const { return m_image.raw_data(m_program_header.p_offset); }
- Elf32_Phdr raw_header() const { return m_program_header; }
+ ElfW(Phdr) raw_header() const { return m_program_header; }
private:
const Image& m_image;
- const Elf32_Phdr& m_program_header;
+ const ElfW(Phdr) & m_program_header;
unsigned m_program_header_index { 0 };
};
@@ -123,7 +123,7 @@ public:
protected:
friend class RelocationSection;
const Image& m_image;
- const Elf32_Shdr& m_section_header;
+ const ElfW(Shdr) & m_section_header;
unsigned m_section_index;
};
@@ -142,7 +142,7 @@ public:
class Relocation {
public:
- Relocation(const Image& image, const Elf32_Rel& rel)
+ Relocation(const Image& image, const ElfW(Rel) & rel)
: m_image(image)
, m_rel(rel)
{
@@ -157,7 +157,7 @@ public:
private:
const Image& m_image;
- const Elf32_Rel& m_rel;
+ const ElfW(Rel) & m_rel;
};
unsigned symbol_count() const;
@@ -207,9 +207,9 @@ public:
private:
const char* raw_data(unsigned offset) const;
- const Elf32_Ehdr& header() const;
- const Elf32_Shdr& section_header(unsigned) const;
- const Elf32_Phdr& program_header_internal(unsigned) const;
+ const ElfW(Ehdr) & header() const;
+ const ElfW(Shdr) & section_header(unsigned) const;
+ const ElfW(Phdr) & program_header_internal(unsigned) const;
StringView table_string(unsigned offset) const;
StringView section_header_table_string(unsigned offset) const;
StringView section_index_to_string(unsigned index) const;
diff --git a/Userland/Libraries/LibELF/Validation.cpp b/Userland/Libraries/LibELF/Validation.cpp
index b06a9eb8d5..8d3f1e23ec 100644
--- a/Userland/Libraries/LibELF/Validation.cpp
+++ b/Userland/Libraries/LibELF/Validation.cpp
@@ -14,7 +14,7 @@
namespace ELF {
-bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool verbose)
+bool validate_elf_header(const ElfW(Ehdr) & elf_header, size_t file_size, bool verbose)
{
if (!IS_ELF(elf_header)) {
if (verbose)
@@ -22,9 +22,16 @@ bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool ve
return false;
}
- if (ELFCLASS32 != elf_header.e_ident[EI_CLASS]) {
+#if ARCH(I386)
+ auto expected_class = ELFCLASS32;
+ auto expected_bitness = 32;
+#else
+ auto expected_class = ELFCLASS64;
+ auto expected_bitness = 64;
+#endif
+ if (expected_class != elf_header.e_ident[EI_CLASS]) {
if (verbose)
- dbgln("File is not a 32 bit ELF file.");
+ dbgln("File is not a {}-bit ELF file.", expected_bitness);
return false;
}
@@ -52,9 +59,17 @@ bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool ve
return false;
}
- if (EM_386 != elf_header.e_machine) {
+#if ARCH(I386)
+ auto expected_machine = EM_386;
+ auto expected_machine_name = "i386";
+#else
+ auto expected_machine = EM_X86_64;
+ auto expected_machine_name = "x86-64";
+#endif
+
+ if (expected_machine != elf_header.e_machine) {
if (verbose)
- dbgln("File has unknown machine ({}), expected i386 (3)!", elf_header.e_machine);
+ dbgln("File has unknown machine ({}), expected {} ({})!", elf_header.e_machine, expected_machine_name, expected_machine);
return false;
}
@@ -70,9 +85,9 @@ bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool ve
return false;
}
- if (sizeof(Elf32_Ehdr) != elf_header.e_ehsize) {
+ if (sizeof(ElfW(Ehdr)) != elf_header.e_ehsize) {
if (verbose)
- dbgln("File has incorrect ELF header size..? ({}), expected ({})!", elf_header.e_ehsize, sizeof(Elf32_Ehdr));
+ dbgln("File has incorrect ELF header size..? ({}), expected ({})!", elf_header.e_ehsize, sizeof(ElfW(Ehdr)));
return false;
}
@@ -112,15 +127,15 @@ bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool ve
return false;
}
- if (0 != elf_header.e_phnum && sizeof(Elf32_Phdr) != elf_header.e_phentsize) {
+ if (0 != elf_header.e_phnum && sizeof(ElfW(Phdr)) != elf_header.e_phentsize) {
if (verbose)
- dbgln("File has incorrect program header size..? ({}), expected ({}).", elf_header.e_phentsize, sizeof(Elf32_Phdr));
+ dbgln("File has incorrect program header size..? ({}), expected ({}).", elf_header.e_phentsize, sizeof(ElfW(Phdr)));
return false;
}
- if (sizeof(Elf32_Shdr) != elf_header.e_shentsize) {
+ if (sizeof(ElfW(Shdr)) != elf_header.e_shentsize) {
if (verbose)
- dbgln("File has incorrect section header size..? ({}), expected ({}).", elf_header.e_shentsize, sizeof(Elf32_Shdr));
+ dbgln("File has incorrect section header size..? ({}), expected ({}).", elf_header.e_shentsize, sizeof(ElfW(Shdr)));
return false;
}
@@ -177,7 +192,7 @@ bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool ve
return true;
}
-bool validate_program_headers(const Elf32_Ehdr& elf_header, size_t file_size, const u8* buffer, size_t buffer_size, String* interpreter_path, bool verbose)
+bool validate_program_headers(const ElfW(Ehdr) & elf_header, size_t file_size, const u8* buffer, size_t buffer_size, String* interpreter_path, bool verbose)
{
Checked<size_t> total_size_of_program_headers = elf_header.e_phnum;
total_size_of_program_headers *= elf_header.e_phentsize;
@@ -204,7 +219,7 @@ bool validate_program_headers(const Elf32_Ehdr& elf_header, size_t file_size, co
}
size_t num_program_headers = elf_header.e_phnum;
- auto program_header_begin = (const Elf32_Phdr*)&(buffer[elf_header.e_phoff]);
+ auto program_header_begin = (const ElfW(Phdr)*)&(buffer[elf_header.e_phoff]);
for (size_t header_index = 0; header_index < num_program_headers; ++header_index) {
auto& program_header = program_header_begin[header_index];
@@ -221,10 +236,18 @@ bool validate_program_headers(const Elf32_Ehdr& elf_header, size_t file_size, co
return false;
}
- if (program_header.p_type == PT_LOAD && program_header.p_align != PAGE_SIZE) {
+ if (program_header.p_type == PT_LOAD && program_header.p_align % (size_t)PAGE_SIZE != 0) {
+ if (elf_header.e_type != ET_CORE) {
+ if (verbose)
+ dbgln("Program header ({}) with p_type PT_LOAD has p_align ({}) not divisible by page size ({})", header_index, program_header.p_align, PAGE_SIZE);
+ return false;
+ }
+ }
+
+ if (program_header.p_type == PT_LOAD && program_header.p_vaddr % program_header.p_align != program_header.p_offset % program_header.p_align) {
if (elf_header.e_type != ET_CORE) {
if (verbose)
- dbgln("Program header ({}) with p_type PT_LOAD has p_align ({}) not equal to page size ({})", header_index, program_header.p_align, PAGE_SIZE);
+ dbgln("Program header ({}) with p_type PT_LOAD has mis-aligned p_vaddr ({:x})", header_index, program_header.p_vaddr);
return false;
}
}
diff --git a/Userland/Libraries/LibELF/Validation.h b/Userland/Libraries/LibELF/Validation.h
index 55c6896d4a..7b097abf8b 100644
--- a/Userland/Libraries/LibELF/Validation.h
+++ b/Userland/Libraries/LibELF/Validation.h
@@ -11,7 +11,7 @@
namespace ELF {
-bool validate_elf_header(const Elf32_Ehdr& elf_header, size_t file_size, bool verbose = true);
-bool validate_program_headers(const Elf32_Ehdr& elf_header, size_t file_size, const u8* buffer, size_t buffer_size, String* interpreter_path, bool verbose = true);
+bool validate_elf_header(const ElfW(Ehdr) & elf_header, size_t file_size, bool verbose = true);
+bool validate_program_headers(const ElfW(Ehdr) & elf_header, size_t file_size, const u8* buffer, size_t buffer_size, String* interpreter_path, bool verbose = true);
} // end namespace ELF