mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
Improve ELF/Trophy loader's error checking
This commit is contained in:
parent
a67b347966
commit
2f333424a6
@ -1556,6 +1556,17 @@ bool fs::dir::open(const std::string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fs::file::strict_read_check(u64 _size, u64 type_size) const
|
||||
{
|
||||
if (usz pos0 = pos(), size0 = size(); pos0 >= size0 || (size0 - pos0) / type_size < _size)
|
||||
{
|
||||
fs::g_tls_error = fs::error::inval;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string& fs::get_config_dir()
|
||||
{
|
||||
// Use magic static
|
||||
|
@ -200,6 +200,8 @@ namespace fs
|
||||
{
|
||||
std::unique_ptr<file_base> m_file;
|
||||
|
||||
bool strict_read_check(u64 size, u64 type_size) const;
|
||||
|
||||
public:
|
||||
// Default constructor
|
||||
file() = default;
|
||||
@ -377,15 +379,24 @@ namespace fs
|
||||
}
|
||||
|
||||
// Read std::basic_string
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str, usz size,
|
||||
template <bool IsStrict = false, typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::basic_string<T>& str, usz _size,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
str.resize(size);
|
||||
return read(&str[0], size * sizeof(T), line, col, file, func) == size * sizeof(T);
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
if (!_size) return true;
|
||||
|
||||
if constexpr (IsStrict)
|
||||
{
|
||||
// If _size arg is too high std::bad_alloc may happen in resize and then we cannot error check
|
||||
if (!strict_read_check(_size, sizeof(T))) return false;
|
||||
}
|
||||
|
||||
str.resize(_size);
|
||||
return read(str.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
|
||||
}
|
||||
|
||||
// Read POD, sizeof(T) is used
|
||||
@ -412,15 +423,23 @@ namespace fs
|
||||
}
|
||||
|
||||
// Read POD std::vector
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, usz size,
|
||||
template <bool IsStrict = false, typename T>
|
||||
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, usz _size,
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* func = __builtin_FUNCTION(),
|
||||
u32 line = __builtin_LINE(),
|
||||
u32 col = __builtin_COLUMN()) const
|
||||
{
|
||||
vec.resize(size);
|
||||
return read(vec.data(), sizeof(T) * size, line, col, file, func) == sizeof(T) * size;
|
||||
if (!m_file) xnull({line, col, file, func});
|
||||
if (!_size) return true;
|
||||
|
||||
if constexpr (IsStrict)
|
||||
{
|
||||
if (!strict_read_check(_size, sizeof(T))) return false;
|
||||
}
|
||||
|
||||
vec.resize(_size);
|
||||
return read(vec.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
|
||||
}
|
||||
|
||||
// Read POD (experimental)
|
||||
|
@ -241,17 +241,15 @@ public:
|
||||
|
||||
if (!(opts & elf_opt::no_programs))
|
||||
{
|
||||
_phdrs.resize(header.e_phnum);
|
||||
stream.seek(offset + header.e_phoff);
|
||||
if (!stream.read(_phdrs))
|
||||
if (!stream.read<true>(_phdrs, header.e_phnum))
|
||||
return set_error(elf_error::stream_phdrs);
|
||||
}
|
||||
|
||||
if (!(opts & elf_opt::no_sections))
|
||||
{
|
||||
shdrs.resize(header.e_shnum);
|
||||
stream.seek(offset + header.e_shoff);
|
||||
if (!stream.read(shdrs))
|
||||
if (!stream.read<true>(shdrs, header.e_shnum))
|
||||
return set_error(elf_error::stream_shdrs);
|
||||
}
|
||||
|
||||
@ -265,9 +263,8 @@ public:
|
||||
|
||||
if (!(opts & elf_opt::no_data))
|
||||
{
|
||||
progs.back().bin.resize(hdr.p_filesz);
|
||||
stream.seek(offset + hdr.p_offset);
|
||||
if (!stream.read(progs.back().bin))
|
||||
if (!stream.read<true>(progs.back().bin, hdr.p_filesz))
|
||||
return set_error(elf_error::stream_data);
|
||||
}
|
||||
}
|
||||
|
@ -40,23 +40,15 @@ pup_object::pup_object(fs::file&& file) : m_file(std::move(file))
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr usz entry_size = sizeof(PUPFileEntry) + sizeof(PUPHashEntry);
|
||||
|
||||
if (!m_header.file_count || (file_size - sizeof(PUPHeader)) / entry_size < m_header.file_count)
|
||||
if (!m_header.file_count)
|
||||
{
|
||||
// These checks before read() are to avoid some std::bad_alloc exceptions when file_count is too large
|
||||
// So we cannot rely on read() for error checking in such cases
|
||||
m_error = pup_error::header_file_count;
|
||||
return;
|
||||
}
|
||||
|
||||
m_file_tbl.resize(m_header.file_count);
|
||||
m_hash_tbl.resize(m_header.file_count);
|
||||
|
||||
if (!m_file.read(m_file_tbl) || !m_file.read(m_hash_tbl))
|
||||
if (!m_file.read<true>(m_file_tbl, m_header.file_count) || !m_file.read<true>(m_hash_tbl, m_header.file_count))
|
||||
{
|
||||
// If these fail it is an unexpected filesystem error, because file size must suffice as we checked in previous checks
|
||||
m_error = pup_error::file_entries;
|
||||
m_error = pup_error::header_file_count;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,12 +52,10 @@ bool TROPUSRLoader::LoadTableHeaders()
|
||||
|
||||
m_file.seek(0x30);
|
||||
m_tableHeaders.clear();
|
||||
m_tableHeaders.resize(m_header.tables_count);
|
||||
|
||||
for (TROPUSRTableHeader& tableHeader : m_tableHeaders)
|
||||
if (!m_file.read<true>(m_tableHeaders, m_header.tables_count))
|
||||
{
|
||||
if (!m_file.read(tableHeader))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -77,25 +75,17 @@ bool TROPUSRLoader::LoadTables()
|
||||
if (tableHeader.type == 4u)
|
||||
{
|
||||
m_table4.clear();
|
||||
m_table4.resize(tableHeader.entries_count);
|
||||
|
||||
for (auto& entry : m_table4)
|
||||
{
|
||||
if (!m_file.read(entry))
|
||||
return false;
|
||||
}
|
||||
if (!m_file.read<true>(m_table4, tableHeader.entries_count))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tableHeader.type == 6u)
|
||||
{
|
||||
m_table6.clear();
|
||||
m_table6.resize(tableHeader.entries_count);
|
||||
|
||||
for (auto& entry : m_table6)
|
||||
{
|
||||
if (!m_file.read(entry))
|
||||
return false;
|
||||
}
|
||||
if (!m_file.read<true>(m_table6, tableHeader.entries_count))
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Other tables
|
||||
|
@ -39,8 +39,8 @@ bool TRPLoader::Install(const std::string& dest, bool /*show*/)
|
||||
for (const TRPEntry& entry : m_entries)
|
||||
{
|
||||
trp_f.seek(entry.offset);
|
||||
buffer.resize(entry.size);
|
||||
if (!trp_f.read(buffer))
|
||||
|
||||
if (!trp_f.read<true>(buffer, entry.size))
|
||||
{
|
||||
trp_log.error("Failed to read TRPEntry at: offset=0x%x, size=0x%x", entry.offset, entry.size);
|
||||
continue; // ???
|
||||
@ -103,10 +103,10 @@ bool TRPLoader::LoadHeader(bool show)
|
||||
if (m_header.trp_version >= 2)
|
||||
{
|
||||
unsigned char hash[20];
|
||||
std::vector<unsigned char> file_contents(m_header.trp_file_size);
|
||||
std::vector<u8> file_contents;
|
||||
|
||||
trp_f.seek(0);
|
||||
if (!trp_f.read(file_contents))
|
||||
if (!trp_f.read<true>(file_contents, m_header.trp_file_size))
|
||||
{
|
||||
trp_log.notice("Failed verifying checksum");
|
||||
}
|
||||
@ -126,18 +126,17 @@ bool TRPLoader::LoadHeader(bool show)
|
||||
}
|
||||
|
||||
m_entries.clear();
|
||||
m_entries.resize(m_header.trp_files_count);
|
||||
|
||||
for (u32 i = 0; i < m_header.trp_files_count; i++)
|
||||
if (!trp_f.read<true>(m_entries, m_header.trp_files_count))
|
||||
{
|
||||
if (!trp_f.read(m_entries[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (show)
|
||||
if (show)
|
||||
{
|
||||
for (const auto& entry : m_entries)
|
||||
{
|
||||
trp_log.notice("TRP entry #%d: %s", m_entries[i].name);
|
||||
trp_log.notice("TRP entry #%u: %s", &entry - m_entries.data(), entry.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user