VolumeVerifier: Add extra validity checks for ticket and TMD
This fixes VolumeVerifier potentially calling TMDReader::GetIOSId for invalid TMDs. VolumeVerifier also has a call to TMDReader::GetContent that doesn't check if the TMD is valid. In practice, this can't get called with an invalid TMD because the previous commit made it so GetContentOffsets returns an empty vector if the TMD is invalid, but I've added a check inside TMDReader::GetContent just to be on the safe side. I also made VolumeVerifier show a specifically worded problem if the ticket or TMD is invalid. Before, invalid TMDs in Wii discs and WADs and invalid tickets in WADs would show a more generic problem.
This commit is contained in:
@@ -322,7 +322,7 @@ u16 TMDReader::GetNumContents() const
|
|||||||
|
|
||||||
bool TMDReader::GetContent(u16 index, Content* content) const
|
bool TMDReader::GetContent(u16 index, Content* content) const
|
||||||
{
|
{
|
||||||
if (index >= GetNumContents())
|
if (!IsValid() || index >= GetNumContents())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -646,44 +646,65 @@ bool VolumeVerifier::CheckPartition(const Partition& partition)
|
|||||||
if (type == PARTITION_UPDATE)
|
if (type == PARTITION_UPDATE)
|
||||||
{
|
{
|
||||||
const IOS::ES::TMDReader& tmd = m_volume.GetTMD(m_volume.GetGamePartition());
|
const IOS::ES::TMDReader& tmd = m_volume.GetTMD(m_volume.GetGamePartition());
|
||||||
|
if (tmd.IsValid())
|
||||||
// IOS9 is the only IOS which can be assumed to exist in a working state on any Wii
|
|
||||||
// regardless of what updates have been installed. At least Mario Party 8
|
|
||||||
// (RM8E01, revision 2) uses IOS9 without having it in its update partition.
|
|
||||||
const u64 ios_ver = tmd.GetIOSId() & 0xFF;
|
|
||||||
bool has_correct_ios = tmd.IsValid() && ios_ver == 9;
|
|
||||||
|
|
||||||
if (!has_correct_ios && tmd.IsValid())
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<FileInfo> file_info = filesystem->FindFileInfo("_sys");
|
const u64 ios_ver = tmd.GetIOSId() & 0xFF;
|
||||||
if (file_info)
|
bool has_correct_ios = false;
|
||||||
|
|
||||||
|
if (ios_ver == 9)
|
||||||
{
|
{
|
||||||
const std::string ios_ver_str = std::to_string(ios_ver);
|
// IOS9 is the only IOS which can be assumed to exist in a working state on any Wii
|
||||||
const std::string correct_ios =
|
// regardless of what updates have been installed. At least Mario Party 8
|
||||||
IsDebugSigned() ? ("firmware.64." + ios_ver_str + ".") : ("ios" + ios_ver_str + "-");
|
// (RM8E01, revision 2) uses IOS9 without having it in its update partition.
|
||||||
for (const FileInfo& f : *file_info)
|
has_correct_ios = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::unique_ptr<FileInfo> file_info = filesystem->FindFileInfo("_sys");
|
||||||
|
if (file_info)
|
||||||
{
|
{
|
||||||
std::string file_name = f.GetName();
|
const std::string ios_ver_str = std::to_string(ios_ver);
|
||||||
Common::ToLower(&file_name);
|
const std::string correct_ios =
|
||||||
if (file_name.starts_with(correct_ios))
|
IsDebugSigned() ? ("firmware.64." + ios_ver_str + ".") : ("ios" + ios_ver_str + "-");
|
||||||
|
for (const FileInfo& f : *file_info)
|
||||||
{
|
{
|
||||||
has_correct_ios = true;
|
std::string file_name = f.GetName();
|
||||||
break;
|
Common::ToLower(&file_name);
|
||||||
|
if (file_name.starts_with(correct_ios))
|
||||||
|
{
|
||||||
|
has_correct_ios = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_correct_ios)
|
if (!has_correct_ios)
|
||||||
{
|
{
|
||||||
// This is reached for hacked dumps where the update partition has been replaced with
|
// This is reached for hacked dumps where the update partition has been replaced with
|
||||||
// a very old update partition so that no updates will be installed.
|
// a very old update partition so that no updates will be installed.
|
||||||
AddProblem(
|
AddProblem(Severity::Low,
|
||||||
Severity::Low,
|
Common::GetStringT(
|
||||||
Common::GetStringT("The update partition does not contain the IOS used by this title."));
|
"The update partition does not contain the IOS used by this title."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IOS::ES::TicketReader& ticket = m_volume.GetTicket(partition);
|
||||||
|
if (!ticket.IsValid())
|
||||||
|
{
|
||||||
|
AddProblem(severity,
|
||||||
|
// i18n: "Ticket" here is a kind of digital authorization to use a certain title
|
||||||
|
// (e.g. a game)
|
||||||
|
Common::FmtFormatT("The {0} partition does not have a valid ticket.", name));
|
||||||
|
}
|
||||||
|
|
||||||
|
const IOS::ES::TMDReader& tmd = m_volume.GetTMD(partition);
|
||||||
|
if (!tmd.IsValid())
|
||||||
|
{
|
||||||
|
AddProblem(severity, Common::FmtFormatT("The {0} partition does not have a valid TMD.", name));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,18 +1002,28 @@ void VolumeVerifier::CheckMisc()
|
|||||||
auto& es = ios.GetESCore();
|
auto& es = ios.GetESCore();
|
||||||
const std::vector<u8>& cert_chain = m_volume.GetCertificateChain(PARTITION_NONE);
|
const std::vector<u8>& cert_chain = m_volume.GetCertificateChain(PARTITION_NONE);
|
||||||
|
|
||||||
if (IOS::HLE::IPC_SUCCESS !=
|
if (!m_ticket.IsValid())
|
||||||
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::Ticket,
|
{
|
||||||
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore, m_ticket,
|
// i18n: "Ticket" here is a kind of digital authorization to use a certain title (e.g. a game)
|
||||||
cert_chain))
|
AddProblem(Severity::High, Common::GetStringT("The ticket is invalid."));
|
||||||
|
}
|
||||||
|
else if (IOS::HLE::IPC_SUCCESS !=
|
||||||
|
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::Ticket,
|
||||||
|
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore, m_ticket,
|
||||||
|
cert_chain))
|
||||||
{
|
{
|
||||||
// i18n: "Ticket" here is a kind of digital authorization to use a certain title (e.g. a game)
|
// i18n: "Ticket" here is a kind of digital authorization to use a certain title (e.g. a game)
|
||||||
AddProblem(Severity::Low, Common::GetStringT("The ticket is not correctly signed."));
|
AddProblem(Severity::Low, Common::GetStringT("The ticket is not correctly signed."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IOS::HLE::IPC_SUCCESS !=
|
if (!tmd.IsValid())
|
||||||
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::TMD,
|
{
|
||||||
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore, tmd, cert_chain))
|
AddProblem(Severity::High, Common::GetStringT("The TMD is invalid."));
|
||||||
|
}
|
||||||
|
else if (IOS::HLE::IPC_SUCCESS !=
|
||||||
|
es.VerifyContainer(IOS::HLE::ESCore::VerifyContainerType::TMD,
|
||||||
|
IOS::HLE::ESCore::VerifyMode::DoNotUpdateCertStore, tmd,
|
||||||
|
cert_chain))
|
||||||
{
|
{
|
||||||
AddProblem(
|
AddProblem(
|
||||||
Severity::Medium,
|
Severity::Medium,
|
||||||
|
|||||||
Reference in New Issue
Block a user