1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

fs::file: always use strict reading mode for large reads (#11206)

This commit is contained in:
Eladash 2021-12-01 18:09:07 +02:00 committed by GitHub
parent f910a152f1
commit f16949c292
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 69 deletions

View File

@ -1658,7 +1658,7 @@ bool fs::dir::open(const std::string& path)
bool fs::file::strict_read_check(u64 _size, u64 type_size) const 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) if (usz pos0 = pos(), size0 = size(); (pos0 >= size0 ? 0 : (size0 - pos0)) / type_size < _size)
{ {
fs::g_tls_error = fs::error::inval; fs::g_tls_error = fs::error::inval;
return false; return false;

View File

@ -205,8 +205,6 @@ namespace fs
{ {
std::unique_ptr<file_base> m_file{}; std::unique_ptr<file_base> m_file{};
bool strict_read_check(u64 size, u64 type_size) const;
public: public:
// Default constructor // Default constructor
file() = default; file() = default;
@ -281,6 +279,9 @@ namespace fs
return m_file->sync(); return m_file->sync();
} }
// Check if the handle is capable of reading (size * type_size) of bytes at the time of calling
bool strict_read_check(u64 size, u64 type_size = 1) const;
// Read the data from the file and return the amount of data written in buffer // Read the data from the file and return the amount of data written in buffer
u64 read(void* buffer, u64 count, u64 read(void* buffer, u64 count,
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
@ -337,8 +338,8 @@ namespace fs
} }
// Write std::basic_string unconditionally // Write std::basic_string unconditionally
template <typename T> template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::basic_string<T>& str, const file& write(const std::basic_string<T>& str,
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(), u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(), const char* file = __builtin_FILE(),
@ -349,8 +350,8 @@ namespace fs
} }
// Write POD unconditionally // Write POD unconditionally
template <typename T> template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const T& data, const file& write(const T& data,
pod_tag_t = pod_tag, pod_tag_t = pod_tag,
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(), u32 col = __builtin_COLUMN(),
@ -362,8 +363,8 @@ namespace fs
} }
// Write POD std::vector unconditionally // Write POD std::vector unconditionally
template <typename T> template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, const file&> write(const std::vector<T>& vec, const file& write(const std::vector<T>& vec,
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(), u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(), const char* file = __builtin_FILE(),
@ -373,84 +374,69 @@ namespace fs
return *this; return *this;
} }
// Read std::basic_string, size must be set by resize() method
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,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
return read(&str[0], str.size() * sizeof(T), line, col, file, func) == str.size() * sizeof(T);
}
// Read std::basic_string // Read std::basic_string
template <bool IsStrict = false, typename T> template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<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, bool read(std::basic_string<T>& str, usz _size = umax,
const char* file = __builtin_FILE(), const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(), const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const u32 col = __builtin_COLUMN()) const
{ {
if (!m_file) xnull({line, col, file, func}); if (!m_file) xnull({line, col, file, func});
if (!_size) return true;
if constexpr (IsStrict) if (_size != umax)
{ {
// If _size arg is too high std::bad_alloc may happen in resize and then we cannot error check // If _size arg is too high std::bad_alloc may happen during resize and then we cannot error check
if (!strict_read_check(_size, sizeof(T))) return false; if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(_size, sizeof(T)))
{
return false;
}
str.resize(_size);
} }
str.resize(_size); return read(str.data(), sizeof(T) * str.size(), line, col, file, func) == sizeof(T) * str.size();
return read(str.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
} }
// Read POD, sizeof(T) is used // Read POD, sizeof(T) is used
template <typename T> template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(T& data, bool read(T& data,
pod_tag_t = pod_tag, pod_tag_t = pod_tag,
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(), u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(), const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION()) const const char* func = __builtin_FUNCTION()) const
{ {
return read(&data, sizeof(T), line, col, file, func) == sizeof(T); return read(std::addressof(data), sizeof(T), line, col, file, func) == sizeof(T);
}
// Read POD std::vector, size must be set by resize() method
template <typename T>
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const
{
return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
} }
// Read POD std::vector // Read POD std::vector
template <bool IsStrict = false, typename T> template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, bool> read(std::vector<T>& vec, usz _size, bool read(std::vector<T>& vec, usz _size = umax,
const char* file = __builtin_FILE(), const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION(), const char* func = __builtin_FUNCTION(),
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN()) const u32 col = __builtin_COLUMN()) const
{ {
if (!m_file) xnull({line, col, file, func}); if (!m_file) xnull({line, col, file, func});
if (!_size) return true;
if constexpr (IsStrict) if (_size != umax)
{ {
if (!strict_read_check(_size, sizeof(T))) return false; // If _size arg is too high std::bad_alloc may happen during resize and then we cannot error check
if ((_size >= 0x10'0000 / sizeof(T)) && !strict_read_check(_size, sizeof(T)))
{
return false;
}
vec.resize(_size);
} }
vec.resize(_size); return read(vec.data(), sizeof(T) * vec.size(), line, col, file, func) == sizeof(T) * vec.size();
return read(vec.data(), sizeof(T) * _size, line, col, file, func) == sizeof(T) * _size;
} }
// Read POD (experimental) // Read POD (experimental)
template <typename T> template <typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T> read( T read(
pod_tag_t = pod_tag, pod_tag_t = pod_tag,
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(), u32 col = __builtin_COLUMN(),
@ -472,13 +458,13 @@ namespace fs
{ {
std::basic_string<T> result; std::basic_string<T> result;
result.resize(size() / sizeof(T)); result.resize(size() / sizeof(T));
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func}); if (seek(0), !read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
return result; return result;
} }
// Read full file to std::vector // Read full file to std::vector
template<typename T> template<typename T> requires (std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>)
std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, std::vector<T>> to_vector( std::vector<T> to_vector(
u32 line = __builtin_LINE(), u32 line = __builtin_LINE(),
u32 col = __builtin_COLUMN(), u32 col = __builtin_COLUMN(),
const char* file = __builtin_FILE(), const char* file = __builtin_FILE(),
@ -486,7 +472,7 @@ namespace fs
{ {
std::vector<T> result; std::vector<T> result;
result.resize(size() / sizeof(T)); result.resize(size() / sizeof(T));
if (seek(0), !read(result, file, func, line, col)) xfail({line, col, file, func}); if (seek(0), !read(result, result.size(), file, func, line, col)) xfail({line, col, file, func});
return result; return result;
} }

View File

@ -226,7 +226,7 @@ namespace rpcs3::utils
// Read null-terminated string // Read null-terminated string
dec_file.seek(0x10); dec_file.seek(0x10);
dec_file.read<true>(edat_content_id, 0x30); dec_file.read(edat_content_id, 0x30);
edat_content_id.resize(std::min<usz>(0x30, edat_content_id.find_first_of('\0'))); edat_content_id.resize(std::min<usz>(0x30, edat_content_id.find_first_of('\0')));
if (edat_content_id != content_id) if (edat_content_id != content_id)
{ {

View File

@ -242,14 +242,14 @@ public:
if (!(opts & elf_opt::no_programs)) if (!(opts & elf_opt::no_programs))
{ {
stream.seek(offset + header.e_phoff); stream.seek(offset + header.e_phoff);
if (!stream.read<true>(_phdrs, header.e_phnum)) if (!stream.read(_phdrs, header.e_phnum))
return set_error(elf_error::stream_phdrs); return set_error(elf_error::stream_phdrs);
} }
if (!(opts & elf_opt::no_sections)) if (!(opts & elf_opt::no_sections))
{ {
stream.seek(offset + header.e_shoff); stream.seek(offset + header.e_shoff);
if (!stream.read<true>(shdrs, header.e_shnum)) if (!stream.read(shdrs, header.e_shnum))
return set_error(elf_error::stream_shdrs); return set_error(elf_error::stream_shdrs);
} }
@ -264,7 +264,7 @@ public:
if (!(opts & elf_opt::no_data)) if (!(opts & elf_opt::no_data))
{ {
stream.seek(offset + hdr.p_offset); stream.seek(offset + hdr.p_offset);
if (!stream.read<true>(progs.back().bin, hdr.p_filesz)) if (!stream.read(progs.back().bin, hdr.p_filesz))
return set_error(elf_error::stream_data); return set_error(elf_error::stream_data);
} }
} }

View File

@ -189,12 +189,12 @@ namespace psf
// Get indices // Get indices
std::vector<def_table_t> indices; std::vector<def_table_t> indices;
PSF_CHECK(stream.read<true>(indices, header.entries_num), corrupt); PSF_CHECK(stream.read(indices, header.entries_num), corrupt);
// Get keys // Get keys
std::string keys; std::string keys;
PSF_CHECK(stream.seek(header.off_key_table) == header.off_key_table, corrupt); PSF_CHECK(stream.seek(header.off_key_table) == header.off_key_table, corrupt);
PSF_CHECK(stream.read<true>(keys, header.off_data_table - header.off_key_table), corrupt); PSF_CHECK(stream.read(keys, header.off_data_table - header.off_key_table), corrupt);
// Load entries // Load entries
for (u32 i = 0; i < header.entries_num; ++i) for (u32 i = 0; i < header.entries_num; ++i)
@ -227,7 +227,7 @@ namespace psf
{ {
// String/array data // String/array data
std::string value; std::string value;
PSF_CHECK(stream.read<true>(value, indices[i].param_len), corrupt); PSF_CHECK(stream.read(value, indices[i].param_len), corrupt);
if (indices[i].param_fmt == format::string) if (indices[i].param_fmt == format::string)
{ {

View File

@ -46,7 +46,7 @@ pup_object::pup_object(fs::file&& file) : m_file(std::move(file))
return; return;
} }
if (!m_file.read<true>(m_file_tbl, m_header.file_count) || !m_file.read<true>(m_hash_tbl, m_header.file_count)) if (!m_file.read(m_file_tbl, m_header.file_count) || !m_file.read(m_hash_tbl, m_header.file_count))
{ {
m_error = pup_error::header_file_count; m_error = pup_error::header_file_count;
return; return;

View File

@ -80,7 +80,7 @@ bool TROPUSRLoader::LoadTableHeaders()
m_file.seek(0x30); m_file.seek(0x30);
m_tableHeaders.clear(); m_tableHeaders.clear();
if (!m_file.read<true>(m_tableHeaders, m_header.tables_count)) if (!m_file.read(m_tableHeaders, m_header.tables_count))
{ {
return false; return false;
} }
@ -103,7 +103,7 @@ bool TROPUSRLoader::LoadTables()
{ {
m_table4.clear(); m_table4.clear();
if (!m_file.read<true>(m_table4, tableHeader.entries_count)) if (!m_file.read(m_table4, tableHeader.entries_count))
return false; return false;
} }
@ -111,7 +111,7 @@ bool TROPUSRLoader::LoadTables()
{ {
m_table6.clear(); m_table6.clear();
if (!m_file.read<true>(m_table6, tableHeader.entries_count)) if (!m_file.read(m_table6, tableHeader.entries_count))
return false; return false;
} }

View File

@ -40,7 +40,7 @@ bool TRPLoader::Install(const std::string& dest, bool /*show*/)
{ {
trp_f.seek(entry.offset); trp_f.seek(entry.offset);
if (!trp_f.read<true>(buffer, entry.size)) if (!trp_f.read(buffer, entry.size))
{ {
trp_log.error("Failed to read TRPEntry at: offset=0x%x, size=0x%x", entry.offset, entry.size); trp_log.error("Failed to read TRPEntry at: offset=0x%x, size=0x%x", entry.offset, entry.size);
continue; // ??? continue; // ???
@ -106,7 +106,7 @@ bool TRPLoader::LoadHeader(bool show)
std::vector<u8> file_contents; std::vector<u8> file_contents;
trp_f.seek(0); trp_f.seek(0);
if (!trp_f.read<true>(file_contents, m_header.trp_file_size)) if (!trp_f.read(file_contents, m_header.trp_file_size))
{ {
trp_log.notice("Failed verifying checksum"); trp_log.notice("Failed verifying checksum");
} }
@ -127,7 +127,7 @@ bool TRPLoader::LoadHeader(bool show)
m_entries.clear(); m_entries.clear();
if (!trp_f.read<true>(m_entries, m_header.trp_files_count)) if (!trp_f.read(m_entries, m_header.trp_files_count))
{ {
return false; return false;
} }