mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
Bugfixes
This commit is contained in:
@@ -839,7 +839,7 @@ bool EDATADecrypter::ReadHeader()
|
||||
// Type 2: Use key from RAP file (RIF key). (also used for type 1 at the moment)
|
||||
else
|
||||
{
|
||||
const std::string rap_path = rpcs3::utils::get_rap_file_path(npdHeader.content_id);
|
||||
const std::string rap_path = rpcs3::utils::get_rap_file_path(npdHeader.get_content_id());
|
||||
|
||||
if (fs::file rap{rap_path}; rap && rap.size() >= sizeof(dec_key))
|
||||
{
|
||||
|
||||
@@ -49,6 +49,12 @@ struct NPD_HEADER
|
||||
u8 dev_hash[0x10];
|
||||
s64 activate_time;
|
||||
s64 expire_time;
|
||||
|
||||
std::string get_content_id() const
|
||||
{
|
||||
const std::string_view id{content_id, sizeof(content_id)};
|
||||
return std::string{id.substr(0, id.find_first_of('\0'))};
|
||||
}
|
||||
};
|
||||
|
||||
struct EDAT_HEADER
|
||||
|
||||
@@ -323,7 +323,7 @@ void supplemental_header::Show() const
|
||||
self_log.notice("Version: 0x%08x", PS3_npdrm_header.npd.version);
|
||||
self_log.notice("License: 0x%08x", PS3_npdrm_header.npd.license);
|
||||
self_log.notice("Type: 0x%08x", PS3_npdrm_header.npd.type);
|
||||
self_log.notice("ContentID: %s", PS3_npdrm_header.npd.content_id);
|
||||
self_log.notice("ContentID: %s", PS3_npdrm_header.npd.get_content_id());
|
||||
self_log.notice("Digest: %s", PS3_npdrm_header.npd.digest);
|
||||
self_log.notice("Inverse digest: %s", PS3_npdrm_header.npd.title_hash);
|
||||
self_log.notice("XOR digest: %s", PS3_npdrm_header.npd.dev_hash);
|
||||
@@ -1065,7 +1065,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
if (npd->license == 1) // Network license.
|
||||
{
|
||||
// Try to find a RAP file to get the key.
|
||||
if (!GetKeyFromRap(npd->content_id, npdrm_key))
|
||||
if (!GetKeyFromRap(npd->get_content_id(), npdrm_key))
|
||||
{
|
||||
self_log.error("Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
@@ -1074,7 +1074,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
else if (npd->license == 2) // Local license.
|
||||
{
|
||||
// Try to find a RAP file to get the key.
|
||||
if (!GetKeyFromRap(npd->content_id, npdrm_key))
|
||||
if (!GetKeyFromRap(npd->get_content_id(), npdrm_key))
|
||||
{
|
||||
self_log.error("Can't find RAP file for NPDRM decryption!");
|
||||
return false;
|
||||
@@ -1283,14 +1283,13 @@ fs::file SELFDecrypter::MakeElf(bool isElf32)
|
||||
return e;
|
||||
}
|
||||
|
||||
bool SELFDecrypter::GetKeyFromRap(const char* content_id, u8* npdrm_key)
|
||||
bool SELFDecrypter::GetKeyFromRap(std::string_view content_id, u8* npdrm_key)
|
||||
{
|
||||
// Set empty RAP key.
|
||||
std::array<u8, 0x10> rap_key {};
|
||||
|
||||
// Try to find a matching RAP file under exdata folder.
|
||||
const std::string ci_str = content_id;
|
||||
const std::string rap_path = rpcs3::utils::get_rap_file_path(ci_str);
|
||||
const std::string rap_path = rpcs3::utils::get_rap_file_path(content_id);
|
||||
|
||||
// Open the RAP file and read the key.
|
||||
const fs::file rap_file(rap_path);
|
||||
@@ -1303,7 +1302,7 @@ bool SELFDecrypter::GetKeyFromRap(const char* content_id, u8* npdrm_key)
|
||||
return false;
|
||||
}
|
||||
|
||||
self_log.notice("Loading RAP file %s.rap", ci_str);
|
||||
self_log.notice("Loading RAP file %s.rap", content_id);
|
||||
|
||||
if (rap_file.read(rap_key.data(), rap_key.size()) != rap_key.size())
|
||||
{
|
||||
|
||||
@@ -478,7 +478,7 @@ public:
|
||||
bool DecryptData();
|
||||
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
|
||||
const NPD_HEADER* GetNPDHeader() const;
|
||||
static bool GetKeyFromRap(const char *content_id, u8 *npdrm_key);
|
||||
static bool GetKeyFromRap(std::string_view content_id, u8 *npdrm_key);
|
||||
|
||||
private:
|
||||
template<typename EHdr, typename SHdr, typename PHdr>
|
||||
|
||||
@@ -1313,7 +1313,7 @@ error_code cellGameDeleteGameData(vm::cptr<char> dirName)
|
||||
{
|
||||
cellGame.warning("cellGameDeleteGameData(dirName=%s)", dirName);
|
||||
|
||||
if (!dirName)
|
||||
if (!dirName || sysutil_check_name_string(dirName.get_ptr(), 1, CELL_GAME_DIRNAME_SIZE) != 0)
|
||||
{
|
||||
return CELL_GAME_ERROR_PARAM;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,22 @@ bool music_selection_context::set(const CellMusicSelectionContext& in)
|
||||
}
|
||||
|
||||
constexpr u32 pos = sizeof(magic);
|
||||
hash = &in.data[pos];
|
||||
|
||||
const std::string_view data{&in.data[pos], sizeof(in.data) - pos};
|
||||
const std::string_view new_hash = data.substr(0, data.find_first_of('\0'));
|
||||
|
||||
const bool is_valid_hash = !new_hash.empty() && std::all_of(new_hash.begin(), new_hash.end(), [](char c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_';
|
||||
});
|
||||
|
||||
if (!is_valid_hash)
|
||||
{
|
||||
cellMusicSelectionContext.error("Invalid music selection context hash, context = %s", context_to_hex(in));
|
||||
return false;
|
||||
}
|
||||
|
||||
hash = std::string{new_hash};
|
||||
|
||||
return load_playlist();
|
||||
}
|
||||
@@ -35,7 +50,7 @@ CellMusicSelectionContext music_selection_context::get() const
|
||||
std::memset(out.data, 0, CELL_MUSIC_SELECTION_CONTEXT_SIZE);
|
||||
std::memcpy(out.data, magic, sizeof(magic));
|
||||
pos += sizeof(magic);
|
||||
std::memcpy(&out.data[pos], hash.c_str(), hash.size());
|
||||
std::memcpy(&out.data[pos], hash.data(), hash.size());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -1333,13 +1333,13 @@ error_code cellRecClose(s32 isDiscard)
|
||||
rec.sink->stop(true);
|
||||
}
|
||||
|
||||
if (fs::is_file(rec.param.filename))
|
||||
if (const std::string local_path = vfs::get(rec.param.filename); fs::is_file(local_path))
|
||||
{
|
||||
cellRec.warning("cellRecClose: removing discarded recording '%s'", rec.param.filename);
|
||||
|
||||
if (!fs::remove_file(rec.param.filename))
|
||||
if (!fs::remove_file(local_path))
|
||||
{
|
||||
cellRec.error("cellRecClose: failed to remove recording '%s'", rec.param.filename);
|
||||
cellRec.error("cellRecClose: failed to remove recording '%s' (%s)", rec.param.filename, fs::g_tls_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +214,16 @@ int check_filename(std::string_view file_path, bool disallow_system_files, bool
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_valid_dir_name(const std::string& dir_name)
|
||||
{
|
||||
if (dir_name.empty() || dir_name.find_first_of('\0') != umax)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return sysutil_check_name_string(dir_name.c_str(), 1, CELL_SAVEDATA_DIRNAME_SIZE) == 0;
|
||||
}
|
||||
|
||||
static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir, const std::string& prefix)
|
||||
{
|
||||
std::vector<SaveDataEntry> save_entries;
|
||||
@@ -251,6 +261,12 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
|
||||
save_entry.subtitle = psf::get_string(psf, "SUB_TITLE");
|
||||
save_entry.details = psf::get_string(psf, "DETAIL");
|
||||
|
||||
if (!is_valid_dir_name(save_entry.dirName))
|
||||
{
|
||||
cellSaveData.error("Savedata '%s' has an invalid SAVEDATA_DIRECTORY entry ('%s')", entry.name, save_entry.dirName);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
||||
{
|
||||
if (entry2.is_directory || check_filename(vfs::unescape(entry2.name), false, true))
|
||||
@@ -848,6 +864,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
save_entry2.subtitle = psf::get_string(psf, "SUB_TITLE");
|
||||
save_entry2.details = psf::get_string(psf, "DETAIL");
|
||||
|
||||
if (!is_valid_dir_name(save_entry2.dirName))
|
||||
{
|
||||
cellSaveData.error("Savedata '%s' has an invalid SAVEDATA_DIRECTORY entry ('%s')", entry.name, save_entry2.dirName);
|
||||
break;
|
||||
}
|
||||
|
||||
for (const auto& entry2 : fs::dir(base_dir + entry.name))
|
||||
{
|
||||
if (entry2.is_directory || check_filename(vfs::unescape(entry2.name), false, true))
|
||||
@@ -1468,6 +1490,12 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
save_entry.escaped = vfs::escape(save_entry.dirName);
|
||||
}
|
||||
|
||||
if (!is_valid_dir_name(save_entry.dirName))
|
||||
{
|
||||
cellSaveData.error("savedata_op(): invalid savedata directory name ('%s')", save_entry.dirName);
|
||||
return {CELL_SAVEDATA_ERROR_BROKEN, save_entry.dirName};
|
||||
}
|
||||
|
||||
const std::string dir_path = base_dir + save_entry.escaped + "/";
|
||||
const std::string old_path = base_dir + ".backup_" + save_entry.escaped + "/";
|
||||
const std::string new_path = base_dir + ".working_" + save_entry.escaped + "/";
|
||||
@@ -2215,7 +2243,7 @@ static NEVER_INLINE error_code savedata_get_list_item(vm::cptr<char> dirName, vm
|
||||
return {CELL_SAVEDATA_ERROR_PARAM, "107"};
|
||||
}
|
||||
|
||||
switch (sysutil_check_name_string(dirName.get_ptr(), 1, CELL_SAVEDATA_DIRLIST_MAX))
|
||||
switch (sysutil_check_name_string(dirName.get_ptr(), 1, CELL_SAVEDATA_DIRNAME_SIZE))
|
||||
{
|
||||
case -1:
|
||||
{
|
||||
|
||||
@@ -699,7 +699,7 @@ error_code npDrmIsAvailable(vm::cptr<u8> k_licensee_addr, vm::cptr<char> drm_pat
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string rap_file = rpcs3::utils::get_rap_file_path(npd.content_id);
|
||||
const std::string rap_file = rpcs3::utils::get_rap_file_path(npd.get_content_id());
|
||||
|
||||
if (fs::file rap_fd{rap_file})
|
||||
{
|
||||
|
||||
@@ -460,7 +460,7 @@ lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename, std::string
|
||||
filename.remove_prefix(cell_fs_path.size());
|
||||
|
||||
const bool is_path = filename.starts_with("/"sv);
|
||||
std::string mp_name = is_path ? std::string{get_path_root_and_trail(filename).first} : std::string(filename);
|
||||
std::string mp_name = is_path ? "/" + std::string{get_path_root_and_trail(filename).first} : std::string(filename);
|
||||
|
||||
const auto check_mp = [&]()
|
||||
{
|
||||
@@ -521,9 +521,6 @@ lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename, std::string
|
||||
*vfs_path = g_cfg_vfs.get_dev_flash3();
|
||||
else
|
||||
*vfs_path = {};
|
||||
|
||||
if (is_path && !is_cell_fs_path && !vfs_path->empty())
|
||||
vfs_path->append(filename.substr(mp_name.size()));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -246,8 +246,8 @@ public:
|
||||
|
||||
lv2_fs_object& operator=(const lv2_fs_object&) = delete;
|
||||
|
||||
// Get the device's root path (e.g. "/dev_hdd0") from a given path
|
||||
// Cut the trail and return it in seccond argument
|
||||
// Get the device's root path (e.g. "dev_hdd0") from a given path
|
||||
// Cut the trail and return it in second argument
|
||||
static std::pair<std::string_view, std::string> get_path_root_and_trail(std::string_view path);
|
||||
|
||||
// Get the device's root path (e.g. "/dev_hdd0") from a given path
|
||||
|
||||
@@ -378,8 +378,27 @@ namespace rpcs3::utils
|
||||
return file_list;
|
||||
}
|
||||
|
||||
static bool is_valid_content_id(std::string_view content_id)
|
||||
{
|
||||
if (content_id.empty() || content_id.size() > 0x30)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::all_of(content_id.begin(), content_id.end(), [](char c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_';
|
||||
});
|
||||
}
|
||||
|
||||
std::string get_rap_file_path(const std::string_view& rap)
|
||||
{
|
||||
if (!is_valid_content_id(rap))
|
||||
{
|
||||
sys_log.error("get_rap_file_path(): invalid content id '%s'", rap);
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string home_dir = get_hdd0_dir() + "home";
|
||||
|
||||
std::string rap_path;
|
||||
@@ -402,6 +421,12 @@ namespace rpcs3::utils
|
||||
|
||||
std::string get_c00_unlock_edat_path(const std::string_view& content_id)
|
||||
{
|
||||
if (!is_valid_content_id(content_id))
|
||||
{
|
||||
sys_log.error("get_c00_unlock_edat_path(): invalid content id '%s'", content_id);
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string home_dir = get_hdd0_dir() + "home";
|
||||
|
||||
std::string edat_path;
|
||||
@@ -448,7 +473,7 @@ namespace rpcs3::utils
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string edat_content_id = npd.content_id;
|
||||
std::string edat_content_id{npd.get_content_id()};
|
||||
|
||||
if (edat_content_id != content_id)
|
||||
{
|
||||
|
||||
+21
-5
@@ -1,11 +1,18 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/VFS.h"
|
||||
#include "Emu/System.h"
|
||||
#include "TRP.h"
|
||||
#include "Crypto/sha1.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
LOG_CHANNEL(trp_log, "Trophy");
|
||||
|
||||
static std::string get_entry_name(const TRPEntry& entry)
|
||||
{
|
||||
const std::string_view name{entry.name, sizeof(entry.name)};
|
||||
return std::string{name.substr(0, name.find_first_of('\0'))};
|
||||
}
|
||||
|
||||
TRPLoader::TRPLoader(const fs::file& f)
|
||||
: m_file(f)
|
||||
{
|
||||
@@ -51,7 +58,16 @@ bool TRPLoader::Install(std::string_view dest, bool /*show*/)
|
||||
}
|
||||
|
||||
// Create the file in the temporary directory
|
||||
const std::string filename = temp + '/' + vfs::escape(entry.name);
|
||||
const std::string entry_name = get_entry_name(entry);
|
||||
const std::string filename = temp + '/' + vfs::escape(entry_name, true);
|
||||
|
||||
if (!Emu.IsPathInsideDir(filename, temp, false))
|
||||
{
|
||||
trp_log.error("Error extracting %s from TRP: target path '%s' would be extracted outside of '%s'", entry_name, filename, temp);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
success = fs::write_file<true>(filename, fs::create + fs::excl, buffer);
|
||||
if (!success)
|
||||
{
|
||||
@@ -160,7 +176,7 @@ bool TRPLoader::LoadHeader(bool show)
|
||||
{
|
||||
for (const auto& entry : m_entries)
|
||||
{
|
||||
trp_log.notice("TRP entry #%u: %s", &entry - m_entries.data(), entry.name);
|
||||
trp_log.notice("TRP entry #%u: %s", &entry - m_entries.data(), get_entry_name(entry));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +200,7 @@ bool TRPLoader::ContainsEntry(std::string_view filename)
|
||||
|
||||
for (const TRPEntry& entry : m_entries)
|
||||
{
|
||||
if (entry.name == filename)
|
||||
if (get_entry_name(entry) == filename)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -202,7 +218,7 @@ void TRPLoader::RemoveEntry(std::string_view filename)
|
||||
std::vector<TRPEntry>::iterator i = m_entries.begin();
|
||||
while (i != m_entries.end())
|
||||
{
|
||||
if (i->name == filename)
|
||||
if (get_entry_name(*i) == filename)
|
||||
{
|
||||
i = m_entries.erase(i);
|
||||
}
|
||||
@@ -222,7 +238,7 @@ void TRPLoader::RenameEntry(std::string_view oldname, std::string_view newname)
|
||||
|
||||
for (TRPEntry& entry : m_entries)
|
||||
{
|
||||
if (entry.name == oldname)
|
||||
if (get_entry_name(entry) == oldname)
|
||||
{
|
||||
strcpy_trunc(entry.name, newname);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user