Files
Pharaoh2k 951e54a3c4 Add content-verified process writes
CMD_PROC_WRITE and write-multi now read writes back before reporting success: a proven DMAP mismatch no longer falls through to mdbg, and failures surface as CMD_ERROR (single write) or typed per-entry codes (invalid / DMAP / verify / mdbg) for write-multi. A transfer whose start address ends in 0xFF backs up one byte to keep the write aligned; that adjacent-byte read-modify-write needs a stable or suspended target.
2026-07-28 12:31:56 +00:00

141 lines
5.5 KiB
C

// SPDX-License-Identifier: GPL-3.0-only
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "sdk_shim.h"
#include "proc.h"
#include "kern_rw_fast.h"
#include "write_policy.h"
extern void *g_proc_rw_mutex;
static int priv_syscall_573(uint64_t *cmd, uint64_t *args, uint64_t *out)
{
int self_pid = getpid();
intptr_t ucred = kernel_get_proc_ucred_fast((pid_t)self_pid);
if (ucred == 0) return -1;
unsigned long saved_authid = 0;
if (kernel_copyout_fast(ucred + 0x58, &saved_authid, sizeof(saved_authid)) != 0) return -1;
if (saved_authid == 0) return -1;
uint64_t priv_authid = 0x4800000000000006ULL;
if (kernel_copyin_fast(&priv_authid, ucred + 0x58, sizeof(priv_authid)) != 0) return -1;
unsigned int syscall_rc = (unsigned int)__crt_syscall(573, cmd, args, out);
int restore_rc = kernel_copyin_fast(&saved_authid, ucred + 0x58, sizeof(saved_authid));
return (restore_rc != 0 ? -1 : 0) | (int)syscall_rc;
}
static int sys_proc_rw_inner(uint32_t pid, uint64_t address, void *data,
uint64_t length, uint64_t *arg5_out, int write)
{
uint64_t cmd_struct[2] = { 1, write ? 0x13ull : 0x12ull };
uint64_t args_struct[4] = { (uint64_t)(int64_t)(int32_t)pid,
address, (uint64_t)data, length };
uint64_t out_struct[2] = { 0, 0 };
if (length == 0) {
if (arg5_out) *arg5_out = 0;
return 0;
}
int syscall_rc = priv_syscall_573(cmd_struct, args_struct, out_struct);
if (syscall_rc != 0 || out_struct[1] != length) return 1;
if (arg5_out) *arg5_out = length;
return 0;
}
static long sys_proc_rw(uint64_t pid, uint64_t address, uint64_t length,
void *data, uint64_t arg5, int write)
{
scePthreadMutexLock(&g_proc_rw_mutex);
int rc;
if (write && length != 0 && ps5debug_write_needs_prefix(address)) {
int diagnostic = ps5debug_write_diagnostics_enabled();
rc = 1;
if (data && length != SIZE_MAX) {
uint8_t *prefixed = (uint8_t *)malloc((size_t)length + 1);
if (prefixed) {
uint64_t read = 0;
rc = sys_proc_rw_inner((uint32_t)pid, address - 1,
prefixed, 1, &read, 0);
if (rc == 0 && read == 1) {
memcpy(prefixed + 1, data, (size_t)length);
uint8_t leading = prefixed[0];
uint64_t wrote = 0;
if (diagnostic) {
klog_printf("[write:mdbg] pid=%u va=0x%llx len=%llu "
"step=prefix-normalize shifted=0x%llx "
"shifted-len=%llu\n",
(uint32_t)pid,
(unsigned long long)address,
(unsigned long long)length,
(unsigned long long)(address - 1),
(unsigned long long)(length + 1));
}
int write_rc =
sys_proc_rw_inner((uint32_t)pid, address - 1,
prefixed, length + 1,
&wrote, 1);
const uint8_t *expected = (const uint8_t *)data;
prefixed[0] = leading ^ 0xFFu;
for (uint64_t i = 0; i < length; i++)
prefixed[i + 1] = expected[i] ^ 0xFFu;
uint64_t verified = 0;
int verify_rc =
sys_proc_rw_inner((uint32_t)pid, address - 1,
prefixed, length + 1,
&verified, 0);
int exact = write_rc == 0 && wrote == length + 1
&& verify_rc == 0
&& verified == length + 1
&& prefixed[0] == leading
&& memcmp(prefixed + 1, expected,
(size_t)length) == 0;
if (diagnostic || !exact) {
klog_printf("[write:mdbg] pid=%u va=0x%llx len=%llu "
"write-rc=%d wrote=%llu verify-rc=%d "
"verified=%llu exact=%d\n",
(uint32_t)pid,
(unsigned long long)address,
(unsigned long long)length,
write_rc, (unsigned long long)wrote,
verify_rc,
(unsigned long long)verified, exact);
}
rc = exact ? 0 : 1;
if (exact && arg5)
*(uint64_t *)(uintptr_t)arg5 = length;
}
free(prefixed);
}
}
} else {
rc = sys_proc_rw_inner((uint32_t)pid, address, data, length,
(uint64_t *)(uintptr_t)arg5, write);
}
scePthreadMutexUnlock(&g_proc_rw_mutex);
return rc;
}
long sys_proc_rw_w0(uint64_t pid, uint64_t address, uint64_t length,
void *data, uint64_t arg5)
{
return sys_proc_rw(pid, address, length, data, arg5, 0);
}
long sys_proc_rw_w1(uint64_t pid, uint64_t address, uint64_t length,
void *data, uint64_t arg5)
{
return sys_proc_rw(pid, address, length, data, arg5, 1);
}