diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index a3777541b5..c8c361d0e1 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -713,11 +713,12 @@ static ErrorOr> find_shebang_interpreter_for_execut ErrorOr> Process::find_elf_interpreter_for_executable(StringView path, ElfW(Ehdr) const& main_executable_header, size_t main_executable_header_size, size_t file_size) { // Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD - String interpreter_path; - if (!ELF::validate_program_headers(main_executable_header, file_size, (u8 const*)&main_executable_header, main_executable_header_size, &interpreter_path)) { + StringBuilder interpreter_path_builder; + if (!TRY(ELF::validate_program_headers(main_executable_header, file_size, (u8 const*)&main_executable_header, main_executable_header_size, &interpreter_path_builder))) { dbgln("exec({}): File has invalid ELF Program headers", path); return ENOEXEC; } + auto interpreter_path = interpreter_path_builder.string_view(); if (!interpreter_path.is_empty()) { dbgln_if(EXEC_DEBUG, "exec({}): Using program interpreter {}", path, interpreter_path); @@ -745,11 +746,12 @@ ErrorOr> Process::find_elf_interpreter_for_executabl } // Not using ErrorOr here because we'll want to do the same thing in userspace in the RTLD - String interpreter_interpreter_path; - if (!ELF::validate_program_headers(*elf_header, interp_metadata.size, (u8*)first_page, nread, &interpreter_interpreter_path)) { + StringBuilder interpreter_interpreter_path_builder; + if (!TRY(ELF::validate_program_headers(*elf_header, interp_metadata.size, (u8*)first_page, nread, &interpreter_interpreter_path_builder))) { dbgln("exec({}): Interpreter ({}) has invalid ELF Program headers", path, interpreter_path); return ENOEXEC; } + auto interpreter_interpreter_path = interpreter_interpreter_path_builder.string_view(); if (!interpreter_interpreter_path.is_empty()) { dbgln("exec({}): Interpreter ({}) has its own interpreter ({})! No thank you!", path, interpreter_path, interpreter_interpreter_path); diff --git a/Userland/DevTools/UserspaceEmulator/Emulator.cpp b/Userland/DevTools/UserspaceEmulator/Emulator.cpp index b02bf7c692..f91cb636db 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator.cpp @@ -166,11 +166,13 @@ bool Emulator::load_elf() VERIFY_NOT_REACHED(); } - String interpreter_path; - if (!ELF::validate_program_headers(*(Elf32_Ehdr const*)elf_image_data.data(), elf_image_data.size(), (u8 const*)elf_image_data.data(), elf_image_data.size(), &interpreter_path)) { + StringBuilder interpreter_path_builder; + auto result_or_error = ELF::validate_program_headers(*(Elf32_Ehdr const*)elf_image_data.data(), elf_image_data.size(), (u8 const*)elf_image_data.data(), elf_image_data.size(), &interpreter_path_builder); + if (result_or_error.is_error() || !result_or_error.value()) { reportln("failed to validate ELF file"); return false; } + auto interpreter_path = interpreter_path_builder.string_view(); VERIFY(!interpreter_path.is_null()); dbgln("interpreter: {}", interpreter_path); diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp index d0332c2f62..d2a986f483 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ b/Userland/Libraries/LibELF/DynamicLoader.cpp @@ -122,8 +122,11 @@ bool DynamicLoader::validate() 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)) + StringBuilder interpreter_path_builder; + auto result_or_error = validate_program_headers(*elf_header, m_file_size, (u8*)m_file_data, m_file_size, &interpreter_path_builder); + if (result_or_error.is_error() || !result_or_error.value()) return false; + m_program_interpreter = interpreter_path_builder.string_view(); return true; } diff --git a/Userland/Libraries/LibELF/Image.cpp b/Userland/Libraries/LibELF/Image.cpp index d610a08291..88e66dee5d 100644 --- a/Userland/Libraries/LibELF/Image.cpp +++ b/Userland/Libraries/LibELF/Image.cpp @@ -126,7 +126,14 @@ bool Image::parse() return false; } - if (!validate_program_headers(header(), m_size, m_buffer, m_size, nullptr, m_verbose_logging)) { + auto result_or_error = validate_program_headers(header(), m_size, m_buffer, m_size, nullptr, m_verbose_logging); + if (result_or_error.is_error()) { + if (m_verbose_logging) + dbgln("ELF::Image::parse(): Failed validating ELF Program Headers"); + m_valid = false; + return false; + } + if (!result_or_error.value()) { if (m_verbose_logging) dbgln("ELF::Image::parse(): ELF Program Headers not valid"); m_valid = false; diff --git a/Userland/Libraries/LibELF/Validation.cpp b/Userland/Libraries/LibELF/Validation.cpp index 525d242286..d363dfef11 100644 --- a/Userland/Libraries/LibELF/Validation.cpp +++ b/Userland/Libraries/LibELF/Validation.cpp @@ -192,7 +192,7 @@ bool validate_elf_header(const ElfW(Ehdr) & elf_header, size_t file_size, bool v return 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) +ErrorOr validate_program_headers(const ElfW(Ehdr) & elf_header, size_t file_size, const u8* buffer, size_t buffer_size, StringBuilder* interpreter_path_builder, bool verbose) { Checked total_size_of_program_headers = elf_header.e_phnum; total_size_of_program_headers *= elf_header.e_phentsize; @@ -268,8 +268,8 @@ bool validate_program_headers(const ElfW(Ehdr) & elf_header, size_t file_size, c dbgln("Found PT_INTERP header ({}), but p_filesz is invalid ({})", header_index, program_header.p_filesz); return false; } - if (interpreter_path) - *interpreter_path = String((const char*)&buffer[program_header.p_offset], program_header.p_filesz - 1); + if (interpreter_path_builder) + TRY(interpreter_path_builder->try_append({ &buffer[program_header.p_offset], program_header.p_filesz - 1 })); break; case PT_LOAD: case PT_DYNAMIC: diff --git a/Userland/Libraries/LibELF/Validation.h b/Userland/Libraries/LibELF/Validation.h index 7b097abf8b..41b6b4957e 100644 --- a/Userland/Libraries/LibELF/Validation.h +++ b/Userland/Libraries/LibELF/Validation.h @@ -8,10 +8,11 @@ #include #include +#include namespace ELF { 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); +ErrorOr validate_program_headers(const ElfW(Ehdr) & elf_header, size_t file_size, const u8* buffer, size_t buffer_size, StringBuilder* interpreter_path_builder, bool verbose = true); } // end namespace ELF diff --git a/Userland/Utilities/file.cpp b/Userland/Utilities/file.cpp index 4728fed7b5..212dfc2a5e 100644 --- a/Userland/Utilities/file.cpp +++ b/Userland/Utilities/file.cpp @@ -67,9 +67,11 @@ static Optional elf_details(String description, const String& path) if (!elf_image.is_valid()) return {}; - String interpreter_path; - if (!ELF::validate_program_headers(*(const ElfW(Ehdr)*)elf_data.data(), elf_data.size(), (const u8*)elf_data.data(), elf_data.size(), &interpreter_path)) + StringBuilder interpreter_path_builder; + auto result_or_error = ELF::validate_program_headers(*(const ElfW(Ehdr)*)elf_data.data(), elf_data.size(), (const u8*)elf_data.data(), elf_data.size(), &interpreter_path_builder); + if (result_or_error.is_error() || !result_or_error.value()) return {}; + auto interpreter_path = interpreter_path_builder.string_view(); auto& header = *reinterpret_cast(elf_data.data()); diff --git a/Userland/Utilities/readelf.cpp b/Userland/Utilities/readelf.cpp index 743a10b4ec..473b4a216a 100644 --- a/Userland/Utilities/readelf.cpp +++ b/Userland/Utilities/readelf.cpp @@ -298,12 +298,13 @@ int main(int argc, char** argv) return -1; } - String interpreter_path; - - if (!ELF::validate_program_headers(*(const ElfW(Ehdr)*)elf_image_data.data(), elf_image_data.size(), (const u8*)elf_image_data.data(), elf_image_data.size(), &interpreter_path)) { + StringBuilder interpreter_path_builder; + auto result_or_error = ELF::validate_program_headers(*(const ElfW(Ehdr)*)elf_image_data.data(), elf_image_data.size(), (const u8*)elf_image_data.data(), elf_image_data.size(), &interpreter_path_builder); + if (result_or_error.is_error() || !result_or_error.value()) { warnln("Invalid ELF headers"); return -1; } + auto interpreter_path = interpreter_path_builder.string_view(); auto& header = *reinterpret_cast(elf_image_data.data()); @@ -311,7 +312,7 @@ int main(int argc, char** argv) if (elf_image.is_dynamic()) { if (interpreter_path.is_null()) { - interpreter_path = "/usr/lib/Loader.so"; + interpreter_path = "/usr/lib/Loader.so"sv; warnln("Warning: Dynamic ELF object has no interpreter path. Using: {}", interpreter_path); }