mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge pull request #8689 from MarcZX10/codex/reject-large-non-elf-early
fix(relinker): reject large non-ELF inputs before allocation
This commit is contained in:
6 files changed
+51
-1
No files matched your search
@@ -2,11 +2,13 @@
|
||||
#define IO_FILEREADER_HPP
|
||||
|
||||
#include <io/IFileReader.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
namespace Io {
|
||||
|
||||
class FileReader : public IFileReader {
|
||||
public:
|
||||
std::vector<std::uint8_t> ReadPrefix(const std::string& path, std::size_t size) const;
|
||||
std::vector<std::uint8_t> Read(const std::string& path) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,9 +3,29 @@
|
||||
#include <domain/Types.hpp>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
|
||||
namespace Io {
|
||||
|
||||
std::vector<std::uint8_t> FileReader::ReadPrefix(const std::string& path, const std::size_t size) const {
|
||||
if (size > static_cast<std::size_t>(std::numeric_limits<std::streamsize>::max()))
|
||||
throw Domain::RelinkerException("File prefix is too large: " + path);
|
||||
const auto native = NativePath(path);
|
||||
std::error_code error;
|
||||
if (!std::filesystem::is_regular_file(native, error))
|
||||
throw Domain::RelinkerException("Cannot open file: " + path);
|
||||
std::ifstream f(native, std::ios::binary);
|
||||
if (!f)
|
||||
throw Domain::RelinkerException("Cannot open file: " + path);
|
||||
std::vector<std::uint8_t> buf(size);
|
||||
f.read(reinterpret_cast<char*>(buf.data()), static_cast<std::streamsize>(size));
|
||||
const auto count = f.gcount();
|
||||
if (f.bad())
|
||||
throw Domain::RelinkerException("Cannot read file: " + path);
|
||||
buf.resize(static_cast<std::size_t>(count));
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> FileReader::Read(const std::string& path) {
|
||||
const auto native = NativePath(path);
|
||||
std::error_code error;
|
||||
|
||||
@@ -40,6 +40,7 @@ struct ConvertedExecutable {
|
||||
ConvertedExecutable Convert(const Cli::Args& args, const std::string& inputPath, const std::string& absPath, const bool mainExecutable, const std::string& targetName, const std::vector<Relinker::GamePatch::PatchEntry>& patches, Cli::ConsoleProgress& progress) {
|
||||
Io::FileReader fileReader;
|
||||
Relinker::ConversionInput input;
|
||||
Relinker::ElfReader(fileReader.ReadPrefix(inputPath, 0x40)).ValidateMagic();
|
||||
input.Executable = fileReader.Read(inputPath);
|
||||
input.InputPath = std::filesystem::absolute(Io::NativePath(inputPath)).lexically_normal();
|
||||
input.OutputPath = Io::NativePath(absPath);
|
||||
|
||||
@@ -10,6 +10,7 @@ class ElfReader : public IElfReader {
|
||||
public:
|
||||
explicit ElfReader(std::vector<std::uint8_t> fileBuffer);
|
||||
|
||||
void ValidateMagic() const;
|
||||
ElfHeader ReadHeader() const override;
|
||||
std::vector<ProgramHeader> ReadProgramHeaders() const override;
|
||||
std::vector<SectionHeader> ReadSectionHeaders() const override;
|
||||
|
||||
@@ -76,7 +76,7 @@ std::uint64_t ElfReader::_readU64At(FileByteOffset fileByteOffset) const {
|
||||
return value;
|
||||
}
|
||||
|
||||
ElfHeader ElfReader::ReadHeader() const {
|
||||
void ElfReader::ValidateMagic() const {
|
||||
if (_fileBuffer.size() < 0x40) {
|
||||
throw RelinkerException("File too small for ELF header");
|
||||
}
|
||||
@@ -90,6 +90,10 @@ ElfHeader ElfReader::ReadHeader() const {
|
||||
_fileBuffer[2] != 'L' || _fileBuffer[3] != 'F') {
|
||||
throw RelinkerException("Invalid ELF magic number: " + formatMagic());
|
||||
}
|
||||
}
|
||||
|
||||
ElfHeader ElfReader::ReadHeader() const {
|
||||
ValidateMagic();
|
||||
if (_fileBuffer[4] != 2 || _fileBuffer[5] != 1 || _fileBuffer[6] != 1)
|
||||
throw RelinkerException("Expected little-endian ELF64 version 1");
|
||||
if (_readU16At(0x12) != 62)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Reject inputs that are not plain ELF files with a message that names what was read."""
|
||||
|
||||
from pathlib import Path
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -23,6 +24,27 @@ def main():
|
||||
convert("eboot.self.kernel", b"\x54\x14\xf5\xee" + bytes(0x1000), "The input is a SELF container, not an ELF")
|
||||
convert("eboot.pkg", b"\x7fCNT" + bytes(0x1000), "Invalid ELF magic number: 7f 43 4e 54")
|
||||
convert("eboot.short", b"\x7fEL", "File too small for ELF header")
|
||||
unsupported_version = bytearray(64)
|
||||
unsupported_version[:4] = b"\x7fELF"
|
||||
unsupported_version[4:7] = b"\x02\x01\x01"
|
||||
unsupported_version[0x12:0x14] = b"\x3e\x00"
|
||||
convert("eboot.unsupported-version", unsupported_version, "Unsupported ELF object version: expected 1")
|
||||
if platform.system() == "Linux":
|
||||
import resource
|
||||
|
||||
source = work / "large-unsupported.pkg"
|
||||
output = work / "large-unsupported.out"
|
||||
with source.open("wb") as stream:
|
||||
stream.write(b"\x7fFIH")
|
||||
stream.truncate(8 * 1024**3)
|
||||
|
||||
def limit_address_space():
|
||||
resource.setrlimit(resource.RLIMIT_AS, (512 * 1024**2, 512 * 1024**2))
|
||||
resource.setrlimit(resource.RLIMIT_CORE, (0, 0))
|
||||
|
||||
result = subprocess.run([str(relinker), "--skip-sce-module", str(source), str(output)],
|
||||
capture_output=True, text=True, timeout=20, preexec_fn=limit_address_space)
|
||||
assert result.returncode == 2 and "Invalid ELF magic number: 7f 46 49 48" in result.stderr and not output.exists(), result
|
||||
print("Input magic diagnostics tests passed")
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user