[VFS] Fix some security issues in StfsContainerDevice code

This commit is contained in:
Triang3l 2019-10-22 08:55:45 +03:00
parent 1005651855
commit e07b0ed2ad
2 changed files with 56 additions and 32 deletions

View File

@ -62,14 +62,13 @@ StfsContainerDevice::~StfsContainerDevice() = default;
bool StfsContainerDevice::Initialize() { bool StfsContainerDevice::Initialize() {
// Resolve a valid STFS file if a directory is given. // Resolve a valid STFS file if a directory is given.
if (filesystem::IsFolder(local_path_) && !ResolveFromFolder(local_path_)) { if (filesystem::IsFolder(local_path_) && !ResolveFromFolder(local_path_)) {
XELOGE("Could not resolve an STFS container given path %s", XELOGE("Could not resolve an STFS container given path %ls",
xe::to_string(local_path_).c_str()); local_path_.c_str());
return false; return false;
} }
if (!filesystem::PathExists(local_path_)) { if (!filesystem::PathExists(local_path_)) {
XELOGE("Path to STFS container does not exist: %s", XELOGE("Path to STFS container does not exist: %ls", local_path_.c_str());
xe::to_string(local_path_).c_str());
return false; return false;
} }
@ -94,10 +93,15 @@ bool StfsContainerDevice::Initialize() {
StfsContainerDevice::Error StfsContainerDevice::MapFiles() { StfsContainerDevice::Error StfsContainerDevice::MapFiles() {
// Map the file containing the STFS Header and read it. // 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); 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) { if (header_result != Error::kSuccess) {
XELOGE("Error reading STFS Header: %d", header_result); XELOGE("Error reading STFS Header: %d", header_result);
return header_result; return header_result;
@ -116,7 +120,7 @@ StfsContainerDevice::Error StfsContainerDevice::MapFiles() {
// the files in the .data folder and can discard the header. // the files in the .data folder and can discard the header.
auto data_fragment_path = local_path_ + L".data"; auto data_fragment_path = local_path_ + L".data";
if (!filesystem::PathExists(data_fragment_path)) { 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()); xe::to_string(data_fragment_path).c_str());
return Error::kErrorFileMismatch; return Error::kErrorFileMismatch;
} }
@ -138,6 +142,11 @@ StfsContainerDevice::Error StfsContainerDevice::MapFiles() {
auto file = fragment_files.at(i); auto file = fragment_files.at(i);
auto path = xe::join_paths(file.path, file.name); auto path = xe::join_paths(file.path, file.name);
auto data = MappedMemory::Open(path, MappedMemory::Mode::kRead); 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))); mmap_.emplace(std::make_pair(i, std::move(data)));
} }
XELOGI("SVOD successfully mapped %d files.", fragment_files.size()); XELOGI("SVOD successfully mapped %d files.", fragment_files.size());
@ -170,19 +179,41 @@ Entry* StfsContainerDevice::ResolvePath(const std::string& path) {
return entry; return entry;
} }
StfsContainerDevice::Error StfsContainerDevice::ReadHeaderAndVerify( StfsContainerDevice::Error StfsContainerDevice::ReadPackageType(
const uint8_t* map_ptr) { const uint8_t* map_ptr, size_t map_size,
// Check signature. StfsPackageType* package_type_out) {
if (memcmp(map_ptr, "LIVE", 4) == 0) { if (map_size < 4) {
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.
return Error::kErrorFileMismatch; 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. // Read header.
if (!header_.Read(map_ptr)) { if (!header_.Read(map_ptr)) {
@ -708,13 +739,6 @@ bool StfsHeader::Read(const uint8_t* p) {
return true; 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<uint32_t>(map->data());
auto magic_bytes = static_cast<char*>(static_cast<void*>(&magic_data));
return std::move(magic_bytes);
}
bool StfsContainerDevice::ResolveFromFolder(const std::wstring& path) { bool StfsContainerDevice::ResolveFromFolder(const std::wstring& path) {
// Scan through folders until a file with magic is found // Scan through folders until a file with magic is found
std::queue<filesystem::FileInfo> queue; std::queue<filesystem::FileInfo> queue;
@ -736,12 +760,11 @@ bool StfsContainerDevice::ResolveFromFolder(const std::wstring& path) {
} else { } else {
// Try to read the file's magic // Try to read the file's magic
auto path = xe::join_paths(current_file.path, current_file.name); auto path = xe::join_paths(current_file.path, current_file.name);
auto magic = ReadMagic(path); auto map = MappedMemory::Open(path, MappedMemory::Mode::kRead, 0, 4);
if (map && ReadPackageType(map->data(), map->size(), nullptr) ==
if (memcmp(magic, "LIVE", 4) == 0 || memcmp(magic, "PIRS", 4) == 0 || Error::kSuccess) {
memcmp(magic, "CON ", 4) == 0) {
local_path_ = xe::join_paths(current_file.path, current_file.name); 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; return true;
} }
} }

View File

@ -197,11 +197,12 @@ class StfsContainerDevice : public Device {
const uint32_t kSTFSHashSpacing = 170; const uint32_t kSTFSHashSpacing = 170;
const char* ReadMagic(const std::wstring& path);
bool ResolveFromFolder(const std::wstring& path); bool ResolveFromFolder(const std::wstring& path);
Error MapFiles(); 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 ReadSVOD();
Error ReadEntrySVOD(uint32_t sector, uint32_t ordinal, Error ReadEntrySVOD(uint32_t sector, uint32_t ordinal,