From cb0d65f1b2e1c5785200ff7806e592eaffd2bccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 20 Jun 2023 23:59:58 +0200 Subject: [PATCH] Attempt to add memory access validation through rc_runtime_invalidate_address --- Core/Config.cpp | 1 + Core/Config.h | 1 + UI/RetroAchievementScreens.cpp | 3 ++- UI/RetroAchievements.cpp | 34 ++++++++++++++++++++++++++++++++-- UI/RetroAchievements.h | 1 + 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index aceb30e087f0..ebe76d625e7b 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -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. diff --git a/Core/Config.h b/Core/Config.h index dae66d8a3133..c05e4a88cb6b 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -492,6 +492,7 @@ struct Config { 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. diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 468a19054d42..c74638dae3fc 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -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"))); diff --git a/UI/RetroAchievements.cpp b/UI/RetroAchievements.cpp index 36d7505ff8ef..db348265b30e 100644 --- a/UI/RetroAchievements.cpp +++ b/UI/RetroAchievements.cpp @@ -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 Achievements::GetAchievementProgress(const Achievement &achievement) { std::pair 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; } diff --git a/UI/RetroAchievements.h b/UI/RetroAchievements.h index 83ba939b1206..4c78bafd07fc 100644 --- a/UI/RetroAchievements.h +++ b/UI/RetroAchievements.h @@ -43,6 +43,7 @@ struct Achievement bool locked; bool active; bool primed; + bool disabled; // due to bad memory access, presumably }; struct Leaderboard