From e07b0ed2ad7812e32007d20f6ec470d227bc6d81 Mon Sep 17 00:00:00 2001 From: Triang3l Date: Tue, 22 Oct 2019 08:55:45 +0300 Subject: [PATCH] [VFS] Fix some security issues in StfsContainerDevice code --- .../vfs/devices/stfs_container_device.cc | 83 ++++++++++++------- src/xenia/vfs/devices/stfs_container_device.h | 5 +- 2 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/xenia/vfs/devices/stfs_container_device.cc b/src/xenia/vfs/devices/stfs_container_device.cc index 728bba7c5..e4fb3bd94 100644 --- a/src/xenia/vfs/devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/stfs_container_device.cc @@ -62,14 +62,13 @@ StfsContainerDevice::~StfsContainerDevice() = default; bool StfsContainerDevice::Initialize() { // Resolve a valid STFS file if a directory is given. if (filesystem::IsFolder(local_path_) && !ResolveFromFolder(local_path_)) { - XELOGE("Could not resolve an STFS container given path %s", - xe::to_string(local_path_).c_str()); + XELOGE("Could not resolve an STFS container given path %ls", + local_path_.c_str()); return false; } if (!filesystem::PathExists(local_path_)) { - XELOGE("Path to STFS container does not exist: %s", - xe::to_string(local_path_).c_str()); + XELOGE("Path to STFS container does not exist: %ls", local_path_.c_str()); return false; } @@ -94,10 +93,15 @@ bool StfsContainerDevice::Initialize() { StfsContainerDevice::Error StfsContainerDevice::MapFiles() { // Map the file containing the STFS Header and read it. - XELOGI("Mapping STFS Header File: %s", xe::to_string(local_path_).c_str()); + XELOGI("Mapping STFS Header file: %ls", local_path_.c_str()); auto header_map = MappedMemory::Open(local_path_, MappedMemory::Mode::kRead); + if (!header_map) { + XELOGE("Error mapping STFS Header file."); + return Error::kErrorReadError; + } - auto header_result = ReadHeaderAndVerify(header_map->data()); + auto header_result = + ReadHeaderAndVerify(header_map->data(), header_map->size()); if (header_result != Error::kSuccess) { XELOGE("Error reading STFS Header: %d", header_result); return header_result; @@ -116,7 +120,7 @@ StfsContainerDevice::Error StfsContainerDevice::MapFiles() { // the files in the .data folder and can discard the header. auto data_fragment_path = local_path_ + L".data"; if (!filesystem::PathExists(data_fragment_path)) { - XELOGE("STFS container is multi-file, but path %s does not exist.", + XELOGE("STFS container is multi-file, but path %ls does not exist.", xe::to_string(data_fragment_path).c_str()); return Error::kErrorFileMismatch; } @@ -138,6 +142,11 @@ StfsContainerDevice::Error StfsContainerDevice::MapFiles() { auto file = fragment_files.at(i); auto path = xe::join_paths(file.path, file.name); auto data = MappedMemory::Open(path, MappedMemory::Mode::kRead); + if (!data) { + XELOGI("Failed to map SVOD file %ls.", path.c_str()); + mmap_.clear(); + return Error::kErrorReadError; + } mmap_.emplace(std::make_pair(i, std::move(data))); } XELOGI("SVOD successfully mapped %d files.", fragment_files.size()); @@ -170,19 +179,41 @@ Entry* StfsContainerDevice::ResolvePath(const std::string& path) { return entry; } -StfsContainerDevice::Error StfsContainerDevice::ReadHeaderAndVerify( - const uint8_t* map_ptr) { - // Check signature. - if (memcmp(map_ptr, "LIVE", 4) == 0) { - package_type_ = StfsPackageType::kLive; - } else if (memcmp(map_ptr, "PIRS", 4) == 0) { - package_type_ = StfsPackageType::kPirs; - } else if (memcmp(map_ptr, "CON ", 4) == 0) { - package_type_ = StfsPackageType::kCon; - } else { - // Unexpected format. +StfsContainerDevice::Error StfsContainerDevice::ReadPackageType( + const uint8_t* map_ptr, size_t map_size, + StfsPackageType* package_type_out) { + if (map_size < 4) { return Error::kErrorFileMismatch; } + if (memcmp(map_ptr, "LIVE", 4) == 0) { + if (package_type_out) { + *package_type_out = StfsPackageType::kLive; + } + return Error::kSuccess; + } + if (memcmp(map_ptr, "PIRS", 4) == 0) { + if (package_type_out) { + *package_type_out = StfsPackageType::kPirs; + } + return Error::kSuccess; + } + if (memcmp(map_ptr, "CON ", 4) == 0) { + if (package_type_out) { + *package_type_out = StfsPackageType::kCon; + } + return Error::kSuccess; + } + // Unexpected format. + return Error::kErrorFileMismatch; +} + +StfsContainerDevice::Error StfsContainerDevice::ReadHeaderAndVerify( + const uint8_t* map_ptr, size_t map_size) { + // Check signature. + auto type_result = ReadPackageType(map_ptr, map_size, &package_type_); + if (type_result != Error::kSuccess) { + return type_result; + } // Read header. if (!header_.Read(map_ptr)) { @@ -708,13 +739,6 @@ bool StfsHeader::Read(const uint8_t* p) { return true; } -const char* StfsContainerDevice::ReadMagic(const std::wstring& path) { - auto map = MappedMemory::Open(path, MappedMemory::Mode::kRead, 0, 4); - auto magic_data = xe::load(map->data()); - auto magic_bytes = static_cast(static_cast(&magic_data)); - return std::move(magic_bytes); -} - bool StfsContainerDevice::ResolveFromFolder(const std::wstring& path) { // Scan through folders until a file with magic is found std::queue queue; @@ -736,12 +760,11 @@ bool StfsContainerDevice::ResolveFromFolder(const std::wstring& path) { } else { // Try to read the file's magic auto path = xe::join_paths(current_file.path, current_file.name); - auto magic = ReadMagic(path); - - if (memcmp(magic, "LIVE", 4) == 0 || memcmp(magic, "PIRS", 4) == 0 || - memcmp(magic, "CON ", 4) == 0) { + auto map = MappedMemory::Open(path, MappedMemory::Mode::kRead, 0, 4); + if (map && ReadPackageType(map->data(), map->size(), nullptr) == + Error::kSuccess) { local_path_ = xe::join_paths(current_file.path, current_file.name); - XELOGI("STFS Package found: %s", xe::to_string(local_path_).c_str()); + XELOGI("STFS Package found: %ls", local_path_.c_str()); return true; } } diff --git a/src/xenia/vfs/devices/stfs_container_device.h b/src/xenia/vfs/devices/stfs_container_device.h index 4ca6618e9..624393e01 100644 --- a/src/xenia/vfs/devices/stfs_container_device.h +++ b/src/xenia/vfs/devices/stfs_container_device.h @@ -197,11 +197,12 @@ class StfsContainerDevice : public Device { const uint32_t kSTFSHashSpacing = 170; - const char* ReadMagic(const std::wstring& path); bool ResolveFromFolder(const std::wstring& path); Error MapFiles(); - Error ReadHeaderAndVerify(const uint8_t* map_ptr); + static Error ReadPackageType(const uint8_t* map_ptr, size_t map_size, + StfsPackageType* package_type_out); + Error ReadHeaderAndVerify(const uint8_t* map_ptr, size_t map_size); Error ReadSVOD(); Error ReadEntrySVOD(uint32_t sector, uint32_t ordinal,