From e8450895a43760c0afd14ebfad3470ec89c65260 Mon Sep 17 00:00:00 2001 From: fanuverse Date: Fri, 18 Sep 2026 16:59:30 +0300 Subject: [PATCH] userd: fix userspace buffer overflow when redirecting and restoring rc file In after_openat(), compat_copy_to_user previously passed sizeof(ORIGIN_RC_FILES[args->local.data3 - 1]) as the copy length. Because ORIGIN_RC_FILES is declared as const char [][64], the sizeof evaluated to 64 bytes (0x40) rather than the actual string length. When userspace (/system/bin/init) opens /system/etc/init/hw/init.rc (28 bytes with null terminator), LLVM libc++ allocates a heap buffer of ~32 bytes. Copying 64 bytes back into userspace caused a 32-byte heap buffer overflow, corrupting adjacent Scudo allocator chunk headers and triggering an immediate SIGSEGV during init::Parser::ParseData() on Android 14. Fix this by: 1. Copying strlen(origin_rc) + 1 bytes in after_openat() to restore only the exact string bounds without overflowing userspace memory. 2. In before_openat(), checking strlen(origin_rc) + 1 >= sizeof(REPLACE_RC_FILE) before attempting an in-place compat_copy_to_user, safely falling back to copy_to_user_stack() for shorter paths like /init.rc. --- kernel/patch/android/userd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/patch/android/userd.c b/kernel/patch/android/userd.c index d2b43b22..dd656bb5 100644 --- a/kernel/patch/android/userd.c +++ b/kernel/patch/android/userd.c @@ -1790,7 +1790,9 @@ static void before_openat(hook_fargs4_t *args, void *udata) } int cplen = 0; - cplen = compat_copy_to_user((void *)filename, REPLACE_RC_FILE, sizeof(REPLACE_RC_FILE)); + 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; args->local.data1 = (uint64_t)args->arg1; @@ -1818,7 +1820,7 @@ static void after_openat(hook_fargs4_t *args, void *udata) compat_copy_to_user( (void *)args->local.data1, origin_rc, - sizeof(ORIGIN_RC_FILES[args->local.data3 - 1])); + strlen(origin_rc) + 1); log_boot("restore rc file: %x\n", args->local.data0); } if (args->local.data2) {