From 7fb79fdf5f9337749ddb85f6497c0aea6846c9fb Mon Sep 17 00:00:00 2001 From: xeropresence <3128949+xeropresence@users.noreply.github.com> Date: Fri, 18 Sep 2026 19:41:56 -0400 Subject: [PATCH] android: redirect init rc paths without overwriting buffers --- kernel/patch/android/userd.c | 54 +++++++++++++----------------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/kernel/patch/android/userd.c b/kernel/patch/android/userd.c index 687fb72a..2781f55d 100644 --- a/kernel/patch/android/userd.c +++ b/kernel/patch/android/userd.c @@ -127,7 +127,6 @@ static const char user_rc_data[] = { // "on property:sys.boot_completed=1\n" " exec -- " SUPERCMD " su -Z " MAGISK_SCTX " exec " APD_PATH " -s %s boot-completed\n" " exec -- " SUPERCMD " su event boot-completed\n" - " exec -- " SUPERCMD " su -Z " MAGISK_SCTX " exec " APD_PATH " uid-listener &\n" " rm " REPLACE_RC_FILE "\n" " exec -- " SUPERCMD " su -Z " MAGISK_SCTX " -c \"mv -f " DEV_LOG_DIR " " AP_LOG_DIR "\"\n" "" @@ -1723,9 +1722,9 @@ static void after_execveat(hook_fargs5_t *args, void *udata) static void before_openat(hook_fargs4_t *args, void *udata) { - // cp len + // redirected flag args->local.data0 = 0; - // cp ptr + // original filename argument args->local.data1 = 0; // unhook flag args->local.data2 = 0; @@ -1739,7 +1738,7 @@ static void before_openat(hook_fargs4_t *args, void *udata) const char __user *filename = (typeof(filename))syscall_argn(args, 1); char buf[256]; long rc = compat_strncpy_from_user(buf, filename, sizeof(buf)); - if (rc <= 0) return; + if (rc <= 0 || rc >= sizeof(buf)) return; int file_count = sizeof(ORIGIN_RC_FILES) / sizeof(ORIGIN_RC_FILES[0]); for (int i = 0; i < file_count; i++) { @@ -1768,7 +1767,7 @@ static void before_openat(hook_fargs4_t *args, void *udata) loff_t off = 0; const char *ori_rc_data = kernel_read_file(origin_rc, &ori_len); - if (!ori_rc_data) goto out; + if (!ori_rc_data) goto free; kernel_write(newfp, ori_rc_data, ori_len, &off); if (off != ori_len) { log_boot("write replace rc error: %x\n", off); @@ -1789,27 +1788,20 @@ static void before_openat(hook_fargs4_t *args, void *udata) goto free; } - int cplen = 0; - /* The in-place rewrite overwrites the caller's own filename buffer, so it is - * only safe when that buffer is at least as long as the replacement string. - * A shorter original path (e.g. "/init.rc") would otherwise be overrun; fall - * through to the stack copy in that case. */ - if (strlen(origin_rc) + 1 >= sizeof(REPLACE_RC_FILE)) { - cplen = compat_copy_to_user((void *)filename, REPLACE_RC_FILE, sizeof(REPLACE_RC_FILE)); - } - if (cplen > 0) { - args->local.data0 = cplen; - /* Read/write the filename argument through syscall_argn rather than - * args->arg1: under the global el0_svc_common hook fargs->arg1 is the - * syscall number (scno), not x1, so direct arg access would restore the - * wrong pointer and the redirect would not take effect. */ - args->local.data1 = syscall_argn(args, 1); - log_boot("redirect rc file: %x\n", args->local.data0); - } else { - void *__user up = copy_to_user_stack(REPLACE_RC_FILE, sizeof(REPLACE_RC_FILE)); - set_syscall_argn(args, 1, (uint64_t)up); - log_boot("redirect rc file stack: %llx\n", up); + /* Never overwrite init's filename allocation: /init.rc is shorter than + * REPLACE_RC_FILE, and the 64-byte table entries are not buffer sizes. */ + uintptr_t sp = current_user_stack_pointer(); + if (sp < sizeof(REPLACE_RC_FILE)) goto free; + sp = (sp - sizeof(REPLACE_RC_FILE)) & ~(uintptr_t)15; + int cplen = compat_copy_to_user((void *__user)sp, REPLACE_RC_FILE, sizeof(REPLACE_RC_FILE)); + if (cplen != sizeof(REPLACE_RC_FILE)) { + log_boot("redirect rc file copy error: %d\n", cplen); + goto free; } + args->local.data0 = 1; + args->local.data1 = syscall_argn(args, 1); + set_syscall_argn(args, 1, sp); + log_boot("redirect rc file stack: %llx\n", sp); free: filp_close(newfp, 0); @@ -1822,15 +1814,9 @@ static void before_openat(hook_fargs4_t *args, void *udata) static void after_openat(hook_fargs4_t *args, void *udata) { - if (args->local.data0 && args->local.data3 > 0) { - const char *origin_rc = ORIGIN_RC_FILES[args->local.data3 - 1]; - /* Restore exactly the bytes the before phase overwrote (data0 is that - * count). Copying the whole 64-byte ORIGIN_RC_FILES slot wrote ~46 - * bytes past the caller's filename buffer and corrupted userspace - * memory, killing init. The untouched tail of the original string is - * still intact, so restoring the overwritten prefix suffices. */ - compat_copy_to_user((void *)args->local.data1, origin_rc, (int)args->local.data0); - log_boot("restore rc file: %x\n", args->local.data0); + if (args->local.data0) { + set_syscall_argn(args, 1, args->local.data1); + log_boot("redirect rc file open result: %ld\n", (long)args->ret); } if (args->local.data2) { unhook_syscalln(__NR_openat, before_openat, after_openat);