From 305084f422bbfd1dd9ae63f0c7680400986165dc Mon Sep 17 00:00:00 2001 From: Herman Semenoff Date: Mon, 30 Mar 2026 00:23:06 +0300 Subject: [PATCH 1/2] HLE: fix global context for md5 and sha1 --- Core/HLE/sceMd5.cpp | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/Core/HLE/sceMd5.cpp b/Core/HLE/sceMd5.cpp index 8ac8d02c61d5..5a82ef19147b 100644 --- a/Core/HLE/sceMd5.cpp +++ b/Core/HLE/sceMd5.cpp @@ -50,8 +50,6 @@ u32 sceKernelUtilsMt19937UInt(u32 ctx) { // TODO: This MD5 stuff needs tests! -static md5_context md5_ctx; - static int sceMd5Digest(u32 dataAddr, u32 len, u32 digestAddr) { DEBUG_LOG(Log::HLE, "sceMd5Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); @@ -67,10 +65,8 @@ static int sceMd5BlockInit(u32 ctxAddr) { if (!Memory::IsValidAddress(ctxAddr)) return -1; - // TODO: Until I know how large a context is, we just go all lazy and use a global context, - // which will work just fine unless games do several MD5 concurrently. - - ppsspp_md5_starts(&md5_ctx); + md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + ppsspp_md5_starts(ctx); return 0; } @@ -79,7 +75,8 @@ static int sceMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, u32 len) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataPtr)) return -1; - ppsspp_md5_update(&md5_ctx, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); + md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + ppsspp_md5_update(ctx, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); return 0; } @@ -88,7 +85,8 @@ static int sceMd5BlockResult(u32 ctxAddr, u32 digestAddr) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; - ppsspp_md5_finish(&md5_ctx, Memory::GetPointerWriteUnchecked(digestAddr)); + md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + ppsspp_md5_finish(ctx, Memory::GetPointerWriteUnchecked(digestAddr)); return 0; } @@ -107,10 +105,8 @@ int sceKernelUtilsMd5BlockInit(u32 ctxAddr) { if (!Memory::IsValidAddress(ctxAddr)) return -1; - // TODO: Until I know how large a context is, we just go all lazy and use a global context, - // which will work just fine unless games do several MD5 concurrently. - - ppsspp_md5_starts(&md5_ctx); + md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + ppsspp_md5_starts(ctx); return 0; } @@ -119,7 +115,8 @@ int sceKernelUtilsMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, int len) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataPtr)) return -1; - ppsspp_md5_update(&md5_ctx, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); + md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + ppsspp_md5_update(ctx, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); return 0; } @@ -128,13 +125,12 @@ int sceKernelUtilsMd5BlockResult(u32 ctxAddr, u32 digestAddr) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; - ppsspp_md5_finish(&md5_ctx, Memory::GetPointerWriteUnchecked(digestAddr)); + md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + ppsspp_md5_finish(ctx, Memory::GetPointerWriteUnchecked(digestAddr)); return 0; } -static sha1_context sha1_ctx; - int sceKernelUtilsSha1Digest(u32 dataAddr, int len, u32 digestAddr) { DEBUG_LOG(Log::HLE, "sceKernelUtilsSha1Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); @@ -150,10 +146,8 @@ int sceKernelUtilsSha1BlockInit(u32 ctxAddr) { if (!Memory::IsValidAddress(ctxAddr)) return -1; - // TODO: Until I know how large a context is, we just go all lazy and use a global context, - // which will work just fine unless games do several MD5 concurrently. - - sha1_starts(&sha1_ctx); + sha1_context *ctx = (sha1_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + sha1_starts(ctx); return 0; } @@ -163,7 +157,8 @@ int sceKernelUtilsSha1BlockUpdate(u32 ctxAddr, u32 dataAddr, int len) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataAddr)) return -1; - sha1_update(&sha1_ctx, Memory::GetPointerWriteUnchecked(dataAddr), (int)len); + sha1_context *ctx = (sha1_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + sha1_update(ctx, Memory::GetPointerWriteUnchecked(dataAddr), (int)len); return 0; } @@ -172,7 +167,8 @@ int sceKernelUtilsSha1BlockResult(u32 ctxAddr, u32 digestAddr) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; - sha1_finish(&sha1_ctx, Memory::GetPointerWriteUnchecked(digestAddr)); + sha1_context *ctx = (sha1_context *)Memory::GetPointerWriteUnchecked(ctxAddr); + sha1_finish(ctx, Memory::GetPointerWriteUnchecked(digestAddr)); return 0; } From 20d393d83ea2567d350f780809e7649634bce124 Mon Sep 17 00:00:00 2001 From: Herman Semenoff Date: Tue, 31 Mar 2026 06:05:54 +0300 Subject: [PATCH 2/2] HLE: fix write to memory without considering size contexts --- Core/HLE/sceMd5.cpp | 65 ++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/Core/HLE/sceMd5.cpp b/Core/HLE/sceMd5.cpp index 5a82ef19147b..a7c820e6e85a 100644 --- a/Core/HLE/sceMd5.cpp +++ b/Core/HLE/sceMd5.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "Common/Crypto/md5.h" #include "Common/Crypto/sha1.h" #include "Common/Data/Random/Rng.h" @@ -50,6 +51,8 @@ u32 sceKernelUtilsMt19937UInt(u32 ctx) { // TODO: This MD5 stuff needs tests! +static std::map md5_contexts; + static int sceMd5Digest(u32 dataAddr, u32 len, u32 digestAddr) { DEBUG_LOG(Log::HLE, "sceMd5Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); @@ -65,8 +68,9 @@ static int sceMd5BlockInit(u32 ctxAddr) { if (!Memory::IsValidAddress(ctxAddr)) return -1; - md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - ppsspp_md5_starts(ctx); + md5_context ctx; + ppsspp_md5_starts(&ctx); + md5_contexts[ctxAddr] = ctx; return 0; } @@ -75,8 +79,11 @@ static int sceMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, u32 len) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataPtr)) return -1; - md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - ppsspp_md5_update(ctx, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); + auto it = md5_contexts.find(ctxAddr); + if (it == md5_contexts.end()) { + return -1; + } + ppsspp_md5_update(&it->second, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); return 0; } @@ -85,8 +92,12 @@ static int sceMd5BlockResult(u32 ctxAddr, u32 digestAddr) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; - md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - ppsspp_md5_finish(ctx, Memory::GetPointerWriteUnchecked(digestAddr)); + auto it = md5_contexts.find(ctxAddr); + if (it == md5_contexts.end()) { + return -1; + } + ppsspp_md5_finish(&it->second, Memory::GetPointerWriteUnchecked(digestAddr)); + md5_contexts.erase(it); return 0; } @@ -105,8 +116,9 @@ int sceKernelUtilsMd5BlockInit(u32 ctxAddr) { if (!Memory::IsValidAddress(ctxAddr)) return -1; - md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - ppsspp_md5_starts(ctx); + md5_context ctx; + ppsspp_md5_starts(&ctx); + md5_contexts[ctxAddr] = ctx; return 0; } @@ -115,8 +127,11 @@ int sceKernelUtilsMd5BlockUpdate(u32 ctxAddr, u32 dataPtr, int len) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataPtr)) return -1; - md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - ppsspp_md5_update(ctx, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); + auto it = md5_contexts.find(ctxAddr); + if (it == md5_contexts.end()) { + return -1; + } + ppsspp_md5_update(&it->second, Memory::GetPointerWriteUnchecked(dataPtr), (int)len); return 0; } @@ -125,12 +140,18 @@ int sceKernelUtilsMd5BlockResult(u32 ctxAddr, u32 digestAddr) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; - md5_context *ctx = (md5_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - ppsspp_md5_finish(ctx, Memory::GetPointerWriteUnchecked(digestAddr)); + auto it = md5_contexts.find(ctxAddr); + if (it == md5_contexts.end()) { + return -1; + } + ppsspp_md5_finish(&it->second, Memory::GetPointerWriteUnchecked(digestAddr)); + md5_contexts.erase(it); return 0; } +static std::map sha1_contexts; + int sceKernelUtilsSha1Digest(u32 dataAddr, int len, u32 digestAddr) { DEBUG_LOG(Log::HLE, "sceKernelUtilsSha1Digest(%08x, %d, %08x)", dataAddr, len, digestAddr); @@ -146,8 +167,9 @@ int sceKernelUtilsSha1BlockInit(u32 ctxAddr) { if (!Memory::IsValidAddress(ctxAddr)) return -1; - sha1_context *ctx = (sha1_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - sha1_starts(ctx); + sha1_context ctx; + sha1_starts(&ctx); + sha1_contexts[ctxAddr] = ctx; return 0; } @@ -157,8 +179,11 @@ int sceKernelUtilsSha1BlockUpdate(u32 ctxAddr, u32 dataAddr, int len) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(dataAddr)) return -1; - sha1_context *ctx = (sha1_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - sha1_update(ctx, Memory::GetPointerWriteUnchecked(dataAddr), (int)len); + auto it = sha1_contexts.find(ctxAddr); + if (it == sha1_contexts.end()) { + return -1; + } + sha1_update(&it->second, Memory::GetPointerWriteUnchecked(dataAddr), (int)len); return 0; } @@ -167,8 +192,12 @@ int sceKernelUtilsSha1BlockResult(u32 ctxAddr, u32 digestAddr) { if (!Memory::IsValidAddress(ctxAddr) || !Memory::IsValidAddress(digestAddr)) return -1; - sha1_context *ctx = (sha1_context *)Memory::GetPointerWriteUnchecked(ctxAddr); - sha1_finish(ctx, Memory::GetPointerWriteUnchecked(digestAddr)); + auto it = sha1_contexts.find(ctxAddr); + if (it == sha1_contexts.end()) { + return -1; + } + sha1_finish(&it->second, Memory::GetPointerWriteUnchecked(digestAddr)); + sha1_contexts.erase(it); return 0; }