From 09f5a45a2dc0a6bd9c643f6c5fb0f9976584c216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Wed, 26 Jun 2024 23:46:27 +0200 Subject: [PATCH] support arbitrary amounts of heap memory --- src/ps5/elfldr.c | 45 ++++++++++++++++++++-- src/ps5/elfldr.h | 9 +++++ src/ps5/hbldr.c | 98 +++++++++++++++++++++++++++++++----------------- src/ps5/pt.c | 65 ++++++++++++++++++++++++++++++++ src/ps5/pt.h | 6 +++ 5 files changed, 186 insertions(+), 37 deletions(-) diff --git a/src/ps5/elfldr.c b/src/ps5/elfldr.c index 0c301b1..0fdc076 100644 --- a/src/ps5/elfldr.c +++ b/src/ps5/elfldr.c @@ -412,10 +412,49 @@ elfldr_prepare_exec(pid_t pid, uint8_t *elf) { } +int +elfldr_set_heap_size(pid_t pid, ssize_t size) { + intptr_t sceLibcHeapSize; + intptr_t sceLibcParam; + intptr_t sceProcParam; + intptr_t Need_sceLibc; + + if(!(sceProcParam=pt_sceKernelGetProcParam(pid))) { + pt_perror(pid, "pt_sceKernelGetProcParam"); + return -1; + } + + if(mdbg_copyout(pid, sceProcParam+56, &sceLibcParam, + sizeof(sceLibcParam))) { + perror("mdbg_copyout"); + return -1; + } + + if(mdbg_copyout(pid, sceLibcParam+16, &sceLibcHeapSize, + sizeof(sceLibcHeapSize))) { + perror("mdbg_copyout"); + return -1; + } + + if(mdbg_setlong(pid, sceLibcHeapSize, size)) { + perror("mdbg_setlong"); + return -1; + } + + if(size != -1) { + return 0; + } + + if(mdbg_copyout(pid, sceLibcParam+72, &Need_sceLibc, + sizeof(Need_sceLibc))) { + perror("mdbg_copyout"); + return -1; + } + + return mdbg_setlong(pid, sceLibcParam+32, Need_sceLibc); +} + -/** - * Set the current working directory. - **/ int elfldr_set_cwd(pid_t pid, const char* cwd) { intptr_t buf; diff --git a/src/ps5/elfldr.h b/src/ps5/elfldr.h index 6860dce..3022d9a 100644 --- a/src/ps5/elfldr.h +++ b/src/ps5/elfldr.h @@ -42,4 +42,13 @@ int elfldr_set_procname(pid_t pid, const char* name); int elfldr_set_stdio(pid_t pid, int stdio); +/** + * Set the current working directory. + **/ int elfldr_set_cwd(pid_t pid, const char* cwd); + + +/** + * Set the heap size for libc. + **/ +int elfldr_set_heap_size(pid_t pid, ssize_t size); diff --git a/src/ps5/hbldr.c b/src/ps5/hbldr.c index 1080658..12b4da0 100644 --- a/src/ps5/hbldr.c +++ b/src/ps5/hbldr.c @@ -15,6 +15,7 @@ along with this program; see the file COPYING. If not, see . */ #include +#include #include #include #include @@ -71,6 +72,10 @@ typedef struct app_launch_ctx { uint32_t app_opt; uint64_t crash_report; uint32_t check_flag; + + // End of SCE fields, the following fields are just used to + // pass arguments to bigapp_launch_thread(). + char **argv; } app_launch_ctx_t; @@ -250,56 +255,78 @@ find_pid(const char* name) { } +static void* +bigapp_launch_thread(void* args) { + app_launch_ctx_t *ctx = (app_launch_ctx_t *)args; + + sceSystemServiceLaunchApp("FAKE00000", ctx->argv, ctx); + + return 0; +} + + static pid_t bigapp_launch(uint32_t user_id, char** argv) { - app_launch_ctx_t ctx = {.user_id = user_id}; - struct kevent evt; - pid_t pid = -1; - int kq; + app_launch_ctx_t ctx = {.user_id = user_id, .argv = argv}; + pthread_t trd; + pid_t parent; + pid_t child; - if((pid=find_pid("SceSysCore.elf")) < 0) { + if((parent=find_pid("SceSysCore.elf")) < 0) { puts("SceSysCore.elf is not running?"); return -1; } - if((kq=kqueue()) < 0) { - perror("kqueue"); + if(pt_attach(parent) < 0) { + perror("pt_attach"); return -1; } - EV_SET(&evt, pid, EVFILT_PROC, EV_ADD, NOTE_FORK | NOTE_TRACK, 0, NULL); - if(kevent(kq, &evt, 1, NULL, 0, NULL) < 0) { - perror("kevent"); - close(kq); + if(pt_follow_fork(parent) < 0) { + perror("pt_follow_fork"); + pt_detach(parent, 0); return -1; } - if(sceSystemServiceLaunchApp("FAKE00000", argv, &ctx) < 0) { - perror("sceSystemServiceLaunchApp"); - close(kq); + if(pt_continue(parent, SIGCONT) < 0) { + perror("pt_continue"); + pt_detach(parent, 0); return -1; } - while(1) { - if(kevent(kq, NULL, 0, &evt, 1, NULL) < 0) { - perror("kevent"); - break; - } + pthread_create(&trd, 0, &bigapp_launch_thread, &ctx); + if((child=pt_await_child(parent)) < 0) { + perror("pt_await_child"); + pt_detach(parent, 0); + return -1; + } - if(evt.fflags & NOTE_CHILD) { - pid = evt.ident; - break; - } + if(pt_detach(parent, 0) < 0) { + perror("pt_detach"); + return -1; + } + + if(pt_follow_exec(child) < 0) { + perror("pt_follow_exec"); + pt_detach(child, SIGKILL); + return -1; + } + + if(pt_continue(child, SIGCONT) < 0) { + perror("pt_continue"); + pt_detach(child, SIGKILL); + return -1; } - if(kill(pid, SIGSTOP) < 0) { - perror("kill"); + if(pt_await_exec(child)) { + perror("pt_await_exec"); + pt_detach(child, SIGKILL); return -1; } - close(kq); + pthread_join(trd, 0); - return pid; + return child; } @@ -349,15 +376,14 @@ bigapp_replace(pid_t pid, uint8_t* elf, const char* progname, int stdio, uint8_t orginstr; char* cwd; - if(!(cwd=getenv("PWD"))) { - cwd = getcwd(buf, sizeof(buf)); + // Let the kernel assign process parameters accessed via sceKernelGetProcParam() + if(pt_syscall(pid, 599)) { + puts("sys_dynlib_process_needed_and_relocate failed"); + //return -1; } - if(pt_attach(pid) < 0) { - perror("pt_attach"); - kill(pid, SIGKILL); - return -1; - } + // Allow libc to allocate arbitrary amount of memory. + elfldr_set_heap_size(pid, -1); if(!(brkpoint=kernel_dynlib_entry_addr(pid, 0))) { puts("kernel_dynlib_entry_addr failed"); @@ -387,6 +413,10 @@ bigapp_replace(pid_t pid, uint8_t* elf, const char* progname, int stdio, return -1; } + if(!(cwd=getenv("PWD"))) { + cwd = getcwd(buf, sizeof(buf)); + } + bigapp_set_argv0(pid, progname); elfldr_set_procname(pid, basename(progname)); elfldr_set_environ(pid, envp); diff --git a/src/ps5/pt.c b/src/ps5/pt.c index 98f5766..fc00a03 100644 --- a/src/ps5/pt.c +++ b/src/ps5/pt.c @@ -108,6 +108,71 @@ pt_detach(pid_t pid, int sig) { return 0; } +int +pt_follow_fork(pid_t pid) { + if(sys_ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) { + return -1; + } + + if(sys_ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1) { + return -1; + } + + return 0; +} + + +int +pt_follow_exec(pid_t pid) { + if(sys_ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1) { + return -1; + } + + return 0; +} + + +pid_t +pt_await_child(pid_t pid) { + struct ptrace_lwpinfo lwpinfo; + + memset(&lwpinfo, 0, sizeof(lwpinfo)); + while(!(lwpinfo.pl_flags & PL_FLAG_FORKED)) { + if(waitpid(pid, NULL, 0) == -1) { + return -1; + } + + if(sys_ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) == -1) { + return -1; + } + } + + if(waitpid(lwpinfo.pl_child_pid, NULL, 0) == -1) { + return -1; + } + + return lwpinfo.pl_child_pid; +} + + +int +pt_await_exec(pid_t pid) { + struct ptrace_lwpinfo lwpinfo; + + memset(&lwpinfo, 0, sizeof(lwpinfo)); + while(!(lwpinfo.pl_flags & PL_FLAG_EXEC)) { + if(waitpid(pid, NULL, 0) == -1) { + return -1; + } + + if(sys_ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) == -1) { + return -1; + } + } + + return 0; +} + int pt_step(int pid) { diff --git a/src/ps5/pt.h b/src/ps5/pt.h index a731c7e..887771e 100644 --- a/src/ps5/pt.h +++ b/src/ps5/pt.h @@ -26,6 +26,12 @@ int pt_detach(pid_t pid, int sig); int pt_step(pid_t pid); int pt_continue(pid_t pid, int sig); +int pt_follow_fork(pid_t pid); +int pt_follow_exec(pid_t pid); + +pid_t pt_await_child(pid_t pid); +int pt_await_exec(pid_t pid); + int pt_getregs(pid_t pid, struct reg *r); int pt_setregs(pid_t pid, const struct reg *r);