diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8799d42..7af9c3b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,7 +59,7 @@ jobs: - arch: arm64 gnu_triple: aarch64-apple-darwin os: iphoneos - minos: 14.0 + minos: 7.0 runs-on: macos-12 env: MBEDTLS_VERSION: 3.3.0 @@ -135,8 +135,8 @@ jobs: if: matrix.os == 'iphoneos' run: | echo "FAKE_PLATFORM=2" >> $GITHUB_ENV - echo "FAKE_SDK=14.0" >> $GITHUB_ENV - echo "FAKE_MINOS=14.0" >> $GITHUB_ENV + echo "FAKE_SDK=7.0" >> $GITHUB_ENV + echo "FAKE_MINOS=7.0" >> $GITHUB_ENV - name: Prepare headers if: matrix.os != 'macosx' diff --git a/.gitignore b/.gitignore index 90c3a06..56b49d6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ build src/*.dmg.c .idea src/stage2/ +src/libcheckra1nhelper.dylib* diff --git a/include/xxd-embedded.h b/include/xxd-embedded.h index 749dbe6..21f0000 100644 --- a/include/xxd-embedded.h +++ b/include/xxd-embedded.h @@ -1,6 +1,10 @@ #ifndef XXD_EMBEDDED_H #define XXD_EMBEDDED_H +#if defined(__APPLE__) +#include +#endif + extern unsigned char checkra1n[]; extern unsigned int checkra1n_len; @@ -13,4 +17,9 @@ extern unsigned int ramdisk_dmg_len; extern unsigned char binpack_dmg[]; extern unsigned int binpack_dmg_len; +#if defined(__APPLE__) && (TARGET_OS_IPHONE || defined(DEV_BUILD)) +extern unsigned char libcheckra1nhelper_dylib[]; +extern unsigned int libcheckra1nhelper_dylib_len; +#endif + #endif diff --git a/src/Makefile b/src/Makefile index 968f406..6c26b35 100644 --- a/src/Makefile +++ b/src/Makefile @@ -4,6 +4,19 @@ OBJECTS = main.o dfuhelper.o devhelper.o lockdown_helper.o OBJECTS += optparse.o override_file.o log.o lock_vars.o credits.o OBJECTS += fake_embedded.o exec_checkra1n.o pongo_helper.o +ifeq (,$(findstring macosx, $(CFLAGS))) +ifneq (,$(findstring version-min=, $(CFLAGS))) +OBJECTS += xxd-libcheckra1nhelper.dylib.o +endif +endif + +ifeq (,$(findstring xxd-libcheckra1nhelper.dylib.o, $(CFLAGS))) +ifeq ($(TARGET_OS),Darwin) +ifeq ($(DEV_BUILD),1) +OBJECTS += xxd-libcheckra1nhelper.dylib.o +endif +endif +endif ifneq ($(NO_RAMDISK),1) OBJECTS += xxd-ramdisk.dmg.o @@ -93,6 +106,9 @@ ifneq (,$(findstring version-min=, $(CFLAGS))) endif endif +libcheckra1nhelper.dylib: chkstk.S + $(CC) $(CFLAGS) $(LDFLAGS) -shared chkstk.S -o libcheckra1nhelper.dylib + checkra1n-kpf-pongo: curl -LO https://cdn.nickchan.lol/palera1n/artifacts/kpf/checkra1n-kpf-pongo @@ -103,6 +119,6 @@ binpack.dmg: curl -LO https://cdn.nickchan.lol/palera1n/c-rewrite/deps/binpack.dmg clean: - rm -rf *.o palera1n checkra1n checkra1n.c palera1n.dSYM + rm -rf *.o palera1n checkra1n checkra1n.c palera1n.dSYM libcheckra1nhelper.dylib .PHONY: all clean diff --git a/src/chkstk.S b/src/chkstk.S new file mode 100644 index 0000000..3b6ba6b --- /dev/null +++ b/src/chkstk.S @@ -0,0 +1,65 @@ +#define _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET -48 +#define _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET -40 + +.align 4 +_thread_chkstk_darwin: + .globl ___chkstk_darwin +___chkstk_darwin: // %w9/x9 == alloca size + stp x10, x11, [sp, #-16] + + // validate that the frame pointer is on our stack (no alt stack) + mrs x10, TPIDRRO_EL0 + + // (%sp - pthread_self()->stackaddr) > 0 ? +#if defined(__ARM64_ARCH_8_32__) + ubfx x9, x9, #0, #32 + ldur w11, [x10, _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET] +#else + ldur x11, [x10, _PTHREAD_STRUCT_DIRECT_STACKADDR_OFFSET] +#endif + subs x11, sp, x11 + b.hs Lprobe + + // %sp <= pthread_self()->stackbottom ? +#if defined(__ARM64_ARCH_8_32__) + ldur w11, [x10, _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET] +#else + ldur x11, [x10, _PTHREAD_STRUCT_DIRECT_STACKBOTTOM_OFFSET] +#endif + mov x10, sp + cmp x10, x11 + b.ls Lprobe + + // %sp - (uintptr_t)%x9 < pthread_self()->stackbottom ? + subs x10, x10, x9 + b.lo Lcrash + cmp x10, x11 + b.lo Lcrash + +Lexit: + ldp x10, x11, [sp, #-16] + ret + +Lcrash: + // POSIX mandates that stack overflow crashes with SIGSEGV + // so load an address in the guard page and dereference it + // + // x11 contains pthread_self()->stackbottom already + ldr x11, [x11, #-8] + // if main_thread caused stack growth with setrlimit() + // fall into Lprobe and eventually cause SIGSEGV. + +Lprobe: + mov x10, sp + cmp x9, #0x1000 + b.lo Lend +Lloop: + sub x10, x10, #0x1000 + ldr x11, [x10] + sub x9, x9, #0x1000 + cmp x9, #0x1000 + b.hi Lloop +Lend: + sub x10, x10, x9 + ldr x11, [x10] + b Lexit diff --git a/src/exec_checkra1n.c b/src/exec_checkra1n.c index ee91dde..4bcbc4a 100644 --- a/src/exec_checkra1n.c +++ b/src/exec_checkra1n.c @@ -11,9 +11,15 @@ #include #include +#include #include #include #include +#include + +#if defined(__APPLE__) +#include +#endif extern char **environ; @@ -53,6 +59,43 @@ int exec_checkra1n() { unlink(checkra1n_path); return -1; } +#if defined(__APPLE__) && (TARGET_OS_IPHONE || defined(DEV_BUILD)) + char* libcheckra1nhelper_dylib_path = NULL; + { + struct utsname name; + uname(&name); + unsigned long darwinMajor = strtoul(name.release, NULL, 10); + assert(darwinMajor != 0); +#if !defined(DEV_BUILD) + if (darwinMajor < 20) { +#endif + libcheckra1nhelper_dylib_path = malloc(strlen(tmpdir) + 40); + snprintf(libcheckra1nhelper_dylib_path, strlen(tmpdir) + 40, "%s/libcheckra1nhelper.dylib.XXXXXX", tmpdir); + int helper_fd = mkstemp(libcheckra1nhelper_dylib_path); + if (helper_fd == -1) { + LOG(LOG_FATAL, "Cannot open temporary file: %d (%s)", errno, strerror(errno)); + return -1; + } + ssize_t didWrite = write(helper_fd, libcheckra1nhelper_dylib, libcheckra1nhelper_dylib_len); + if ((unsigned int)didWrite != libcheckra1nhelper_dylib_len) { + LOG(LOG_FATAL, "Size written does not match expected: %lld != %d: %d (%s)", didWrite, libcheckra1nhelper_dylib_len, errno, strerror(errno)); + close(helper_fd); + unlink(libcheckra1nhelper_dylib_path); + return -1; + } + close(helper_fd); + ret = chmod(libcheckra1nhelper_dylib_path, 0700); + if (ret) { + LOG(LOG_FATAL, "Cannot chmod %s: %d (%s)", libcheckra1nhelper_dylib_path, errno, strerror(errno)); + unlink(libcheckra1nhelper_dylib_path); + return -1; + } + setenv("DYLD_INSERT_LIBRARIES", libcheckra1nhelper_dylib_path, 1); +#if !defined(DEV_BUILD) + } +#endif + } +#endif checkra1n_exec: {}; char args[0x10] = "-pE"; if (checkrain_option_enabled(host_flags, host_option_demote)) strncat(args, "d", 0xf); @@ -80,6 +123,15 @@ checkra1n_exec: {}; free(checkra1n_path); checkra1n_path = NULL; } +#if defined(__APPLE__) && (TARGET_OS_IPHONE || defined(DEV_BUILD)) + if (libcheckra1nhelper_dylib_path != NULL) { + unlink(libcheckra1nhelper_dylib_path); + unsetenv("DYLD_INSERT_LIBRARIES"); + unsetenv("DYLD_FORCE_FLAT_NAMESPACE"); + free(libcheckra1nhelper_dylib_path); + libcheckra1nhelper_dylib_path = NULL; + } +#endif waitpid(pid, NULL, 0); return 0; }