diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index 8894a7d9a..3f3520ed5 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -11,6 +11,7 @@ #include "system.h" #include "util/cd_image.h" +#include "util/elf_file.h" #include "util/http_downloader.h" #include "util/image.h" #include "util/ini_settings_interface.h" @@ -199,6 +200,18 @@ bool GameList::GetExeListEntry(const std::string& path, GameList::Entry* entry) // Who knows entry->region = DiscRegion::Other; } + else if (StringUtil::EndsWithNoCase(filename, ".elf")) + { + ELFFile::Elf32_Ehdr header; + if (std::fread(&header, sizeof(header), 1, fp.get()) != 1 || !ELFFile::IsValidElfHeader(header)) + { + WARNING_LOG("{} is not a valid ELF.", path); + return false; + } + + // Who knows + entry->region = DiscRegion::Other; + } else { BIOS::PSEXEHeader header; diff --git a/src/util/elf_file.cpp b/src/util/elf_file.cpp index 0e92a8f33..1ae3f298f 100644 --- a/src/util/elf_file.cpp +++ b/src/util/elf_file.cpp @@ -9,6 +9,7 @@ LOG_CHANNEL(FileLoader); +static constexpr const u8 EXPECTED_ELF_HEADER[4] = {'\177', 'E', 'L', 'F'}; static constexpr s64 MAX_ELF_FILE_SIZE = 32 * 1024 * 1024; ELFFile::ELFFile() = default; @@ -113,9 +114,8 @@ bool ELFFile::Open(DataArray data, Error* error) { m_data = std::move(data); - static constexpr const u8 EXPECTED_HEADER[4] = {'\177', 'E', 'L', 'F'}; - - if (m_data.size() < sizeof(Elf32_Ehdr) || std::memcmp(m_data.data(), EXPECTED_HEADER, sizeof(EXPECTED_HEADER)) != 0) + if (m_data.size() < sizeof(Elf32_Ehdr) || + std::memcmp(m_data.data(), EXPECTED_ELF_HEADER, sizeof(EXPECTED_ELF_HEADER)) != 0) { Error::SetStringView(error, "Invalid header."); return false; @@ -202,3 +202,32 @@ bool ELFFile::LoadExecutableSections(const LoadExecutableSectionCallback& callba return true; } + +bool ELFFile::IsValidElfHeader(const std::span data, Error* error /*= nullptr*/) +{ + if (data.size() < sizeof(Elf32_Ehdr)) + { + Error::SetStringView(error, "Invalid header."); + return false; + } + + return IsValidElfHeader(reinterpret_cast(*data.data()), error); +} + +bool ELFFile::IsValidElfHeader(const Elf32_Ehdr& header, Error* error /* = nullptr */) +{ + if (std::memcmp(header.e_ident, EXPECTED_ELF_HEADER, sizeof(EXPECTED_ELF_HEADER)) != 0) + { + Error::SetStringView(error, "Invalid header."); + return false; + } + + if (header.e_machine != EM_MIPS) + { + Error::SetStringFmt(error, "Unsupported machine type {}.", header.e_machine); + return false; + } + + // probably fine + return true; +} diff --git a/src/util/elf_file.h b/src/util/elf_file.h index 29d5205de..7f4fb33bf 100644 --- a/src/util/elf_file.h +++ b/src/util/elf_file.h @@ -94,6 +94,9 @@ public: ELFFile(); ~ELFFile(); + static bool IsValidElfHeader(const std::span data, Error* error = nullptr); + static bool IsValidElfHeader(const Elf32_Ehdr& header, Error* error = nullptr); + const Elf32_Ehdr& GetELFHeader() const; u32 GetEntryPoint() const;