Attempt to add memory access validation through rc_runtime_invalidate_address

This commit is contained in:
Henrik Rydgård 2023-06-20 23:59:58 +02:00
parent da36d78d4f
commit 3218422a69
5 changed files with 37 additions and 3 deletions

View file

@ -273,6 +273,7 @@ static const ConfigSetting achievementSettings[] = {
ConfigSetting("AchievementsChallengeMode", &g_Config.bAchievementsChallengeMode, false, CfgFlag::DEFAULT),
ConfigSetting("AchievementsSoundEffects", &g_Config.bAchievementsSoundEffects, true, CfgFlag::DEFAULT),
ConfigSetting("AchievementsNotifications", &g_Config.bAchievementsNotifications, true, CfgFlag::DEFAULT),
ConfigSetting("AchievementsLogBadMemReads", &g_Config.bAchievementsLogBadMemReads, false, CfgFlag::DEFAULT),
// Achievements login info. Note that password is NOT stored, only a login token.
// Still, we may wanna store it more securely than in PPSSPP.ini, especially on Android.

View file

@ -492,6 +492,7 @@ public:
bool bAchievementsChallengeMode;
bool bAchievementsSoundEffects;
bool bAchievementsNotifications;
bool bAchievementsLogBadMemReads;
// Achivements login info. Note that password is NOT stored, only a login token.
// Still, we may wanna store it more securely than in PPSSPP.ini, especially on Android.

View file

@ -104,7 +104,8 @@ void RetroAchievementsSettingsScreen::CreateSettingsTab(UI::ViewGroup *viewGroup
using namespace UI;
viewGroup->Add(new ItemHeader(ac->T("Settings")));
viewGroup->Add(new CheckBox(&g_Config.bAchievementsRichPresence, ac->T("Rich Presence")));
viewGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects")));
viewGroup->Add(new CheckBox(&g_Config.bAchievementsSoundEffects, ac->T("Sound Effects"))); // not yet implemented
viewGroup->Add(new CheckBox(&g_Config.bAchievementsLogBadMemReads, ac->T("Log bad memory accesses")));
// Not yet fully implemented
// viewGroup->Add(new CheckBox(&g_Config.bAchievementsChallengeMode, ac->T("Challenge Mode")));

View file

@ -173,6 +173,7 @@ static void DeactivateAchievement(Achievement *achievement);
static void UnlockAchievement(u32 achievement_id, bool add_notification = true);
static void AchievementPrimed(u32 achievement_id);
static void AchievementUnprimed(u32 achievement_id);
static void AchievementDisabled(u32 achievement_id);
static void SubmitLeaderboard(u32 leaderboard_id, int value);
static void SendPing();
static void SendPlaying();
@ -245,6 +246,8 @@ static u64 g_badMemoryAccessCount = 0;
const std::string g_gameIconCachePrefix = "game:";
const std::string g_iconCachePrefix = "badge:";
#define PSP_MEMORY_OFFSET 0x08000000
// TODO: Add an icon cache as a string map. We won't cache achievement icons across sessions, let's just
// download them as we go.
@ -1171,6 +1174,10 @@ void Achievements::GetUserUnlocks()
request.Send(GetUserUnlocksCallback);
}
static int ValidateAddress(unsigned address) {
return Memory::IsValidAddress(address + PSP_MEMORY_OFFSET) ? 1 : 0;
}
void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
Common::HTTPDownloader::Request::Data data)
{
@ -1318,6 +1325,9 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
{
ClearGameInfo();
}
// Hook up memory validation (doesn't seem to do much though?)
rc_runtime_validate_addresses(&s_rcheevos_runtime, &Achievements::CheevosEventHandler, &ValidateAddress);
}
void Achievements::GetLbInfoCallback(s32 status_code, std::string content_type,
@ -1962,6 +1972,19 @@ void Achievements::AchievementUnprimed(u32 achievement_id)
s_primed_achievement_count.fetch_sub(std::memory_order_acq_rel);
}
void Achievements::AchievementDisabled(u32 achievement_id)
{
std::unique_lock lock(s_achievements_mutex);
Achievement *achievement = GetMutableAchievementByID(achievement_id);
if (!achievement)
return;
// Have not seen this trigger yet, despite games doing bad memory accesses.
INFO_LOG(ACHIEVEMENTS, "Achievement disabled due to invalid memory access: %s", achievement->title);
achievement->disabled = true;
}
std::pair<u32, u32> Achievements::GetAchievementProgress(const Achievement &achievement)
{
std::pair<u32, u32> result;
@ -2037,6 +2060,10 @@ void Achievements::CheevosEventHandler(const rc_runtime_event_t *runtime_event)
AchievementUnprimed(runtime_event->id);
break;
case RC_RUNTIME_EVENT_ACHIEVEMENT_DISABLED:
AchievementDisabled(runtime_event->id);
break;
case RC_RUNTIME_EVENT_LBOARD_TRIGGERED:
SubmitLeaderboard(runtime_event->id, runtime_event->value);
break;
@ -2048,13 +2075,16 @@ void Achievements::CheevosEventHandler(const rc_runtime_event_t *runtime_event)
unsigned Achievements::PeekMemory(unsigned address, unsigned num_bytes, void *ud) {
// Unclear why achievements are defined with this offset, but they are and it can't be changed now, so we roll with it.
address += 0x08000000;
address += PSP_MEMORY_OFFSET;
if (!Memory::IsValidAddress(address)) {
// Some achievement packs are really, really spammy.
// So we'll just count the bad accesses.
g_badMemoryAccessCount++;
// WARN_LOG(G3D, "RetroAchievements PeekMemory: Bad address %08x (%d bytes)", address, num_bytes);
if (g_Config.bAchievementsLogBadMemReads) {
WARN_LOG(G3D, "RetroAchievements PeekMemory: Bad address %08x (%d bytes)", address, num_bytes);
}
return 0;
}

View file

@ -43,6 +43,7 @@ struct Achievement
bool locked;
bool active;
bool primed;
bool disabled; // due to bad memory access, presumably
};
struct Leaderboard