diff --git a/src/kernel/emulation/linux/process/execve.c b/src/kernel/emulation/linux/process/execve.c index 1c843c25a..a613a96fc 100644 --- a/src/kernel/emulation/linux/process/execve.c +++ b/src/kernel/emulation/linux/process/execve.c @@ -34,121 +34,7 @@ static inline bool isspace(char c) long sys_execve(char* fname, char** argvp, char** envp) { - int ret, fd, len; - char mldr_path[256]; - union - { - uint32_t magic; - char magic_array[256]; - } m; - - // Ideally, if everybody used binfmt_misc to allow direct - // execution of Mach-O binaries under Darling, this wouldn't - // be necessary. But we cannot rely on that. - - fd = sys_open(fname, BSD_O_RDONLY, 0); - if (fd < 0) - return fd; - - ret = sys_read(fd, m.magic_array, sizeof(m.magic_array)); - sys_close(fd); - - if (ret < 4) - return -ENOEXEC; - - len = LINUX_SYSCALL(__NR_readlink, "/proc/self/exe", mldr_path, sizeof(mldr_path)-1); - if (len < 0) - return -ENOEXEC; - mldr_path[len] = '\0'; - - if (m.magic == MH_MAGIC || m.magic == MH_CIGAM - || m.magic == MH_MAGIC_64 || m.magic == MH_CIGAM_64 - || m.magic == FAT_MAGIC || m.magic == FAT_CIGAM) - { - // It is a Mach-O file - int i; - char** modargvp; - char *buf; - - // Prepend mldr path - len = 0; - - // Count arguments - while (argvp[len++]); - - // Allocate a new argvp, execute mldr_path - modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+1)); - buf = __builtin_alloca(strlen(mldr_path) + 2 + strlen(fname)); - - strcpy(buf, mldr_path); - strcat(buf, "!"); - strcat(buf, fname); - modargvp[0] = buf; - - for (i = 1; i < len+1; i++) - modargvp[i] = argvp[i-1]; - - argvp = modargvp; - fname = mldr_path; - } - // Shebang support - else if (m.magic_array[0] == '#' && m.magic_array[1] == '!') - { - char *nl, *interp, *arg; - char** modargvp; - int i, j; - - nl = memchr(m.magic_array, '\n', sizeof(m.magic_array)); - if (nl == NULL) - return -ENOEXEC; - - *nl = '\0'; - - for (i = 2; isspace(m.magic_array[i]); i++); - - interp = &m.magic_array[i]; - - for (i = 0; !isspace(interp[i]) && interp[i]; i++); - - if (interp[i] == '\0') - arg = NULL; - else - arg = &interp[i]; - - if (arg != NULL) - { - *arg = '\0'; // terminate interp - arg++; - - while (isspace(*arg)) - arg++; - if (*arg == '\0') - arg = NULL; // no argument, just whitespace - } - - // Count original arguments - while (argvp[len++]); - - // Allocate a new argvp - modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+3)); - - i = 0; - - modargvp[i++] = mldr_path; - modargvp[i++] = interp; - if (arg != NULL) - modargvp[i++] = arg; - modargvp[i] = fname; - - // Append original arguments - for (j = 1; j < len+1; j++) - modargvp[i+j] = argvp[j]; - - argvp = modargvp; - fname = mldr_path; - } - - // otherwise, it's a native Linux executable (ELF) + int ret; linux_sigset_t set; set = (1ull << (SIGNAL_SIGEXC_TOGGLE-1)); diff --git a/src/lkm b/src/lkm index 9f3be3190..9648becf4 160000 --- a/src/lkm +++ b/src/lkm @@ -1 +1 @@ -Subproject commit 9f3be31908437c6292709364224f5d9cae872d5b +Subproject commit 9648becf4a32ffb0208c401c1ebce26f7dfc2ee9 diff --git a/src/startup/CMakeLists.txt b/src/startup/CMakeLists.txt index 774a26322..0bac7a418 100644 --- a/src/startup/CMakeLists.txt +++ b/src/startup/CMakeLists.txt @@ -20,28 +20,9 @@ target_link_libraries(darling -lutil) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -set(mldr_sources - mldr.c - threads.c - gdb.c - commpage.c - elfcalls.c -) -add_executable(mldr ${mldr_sources}) -target_link_libraries(mldr pthread dl rt) - -add_executable(mldr32 ${mldr_sources}) -target_link_libraries(mldr32 pthread dl rt) -set_target_properties(mldr32 - PROPERTIES - COMPILE_FLAGS "-m32" - LINK_FLAGS "-m32" -) - add_executable(wrapgen wrapgen/wrapgen.cpp) target_link_libraries(wrapgen dl) -install(TARGETS mldr mldr32 DESTINATION libexec/darling/bin) install(TARGETS darling DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE @@ -49,9 +30,6 @@ install(TARGETS darling DESTINATION bin WORLD_READ WORLD_EXECUTE SETUID) -include(setcap) -setcap(libexec/darling/bin/mldr cap_sys_rawio,cap_sys_ptrace+ep) -setcap(libexec/darling/bin/mldr32 cap_sys_rawio,cap_sys_ptrace+ep) # This tool is useful for packaging to detect ELF dependencies inside Mach-O libraries, # which standard distro tools cannot do. diff --git a/src/startup/darling.c b/src/startup/darling.c index a613ccd03..475dc5e7d 100644 --- a/src/startup/darling.c +++ b/src/startup/darling.c @@ -47,8 +47,6 @@ along with Darling. If not, see . #include "darling.h" #include "darling-config.h" -#define MLDR_PATH "/bin/mldr" - // Between Linux 4.9 and 4.11, a strange bug has been introduced // which prevents connecting to Unix sockets if the socket was // created in a different mount namespace or under overlayfs @@ -866,7 +864,7 @@ void spawnLaunchd(void) puts("Bootstrapping the container with launchd..."); // putenv("KQUEUE_DEBUG=1"); - execl(MLDR_PATH, "mldr!/sbin/launchd", "launchd", NULL); + execl("/sbin/launchd", "launchd", NULL); fprintf(stderr, "Failed to exec launchd: %s\n", strerror(errno)); abort(); @@ -1093,7 +1091,7 @@ pid_t getInitProcess() } fclose(fp); - if (strcmp(exeBuf, "mldr") != 0) + if (strcmp(exeBuf, "launchd") != 0) { unlink(pidPath); return 0; diff --git a/src/startup/loader.c b/src/startup/loader.c deleted file mode 100644 index 85b561590..000000000 --- a/src/startup/loader.c +++ /dev/null @@ -1,242 +0,0 @@ - -// Definitions: -// FUNCTION_NAME (load32/load64) -// SEGMENT_STRUCT (segment_command/SEGMENT_STRUCT) -// SEGMENT_COMMAND (LC_SEGMENT/SEGMENT_COMMAND) -// MACH_HEADER_STRUCT (mach_header/MACH_HEADER_STRUCT) -// SECTION_STRUCT (section/SECTION_STRUCT) - -#if defined(GEN_64BIT) -# define FUNCTION_NAME load64 -# define SEGMENT_STRUCT segment_command_64 -# define SEGMENT_COMMAND LC_SEGMENT_64 -# define MACH_HEADER_STRUCT mach_header_64 -# define SECTION_STRUCT section_64 -# define MAP_EXTRA 0 -#elif defined(GEN_32BIT) -# define FUNCTION_NAME load32 -# define SEGMENT_STRUCT segment_command -# define SEGMENT_COMMAND LC_SEGMENT -# define MACH_HEADER_STRUCT mach_header -# define SECTION_STRUCT section -# define MAP_EXTRA MAP_32BIT -#else -# error See above -#endif - -void FUNCTION_NAME(int fd, uintptr_t* entryPoint_out, uintptr_t* mh_out) -{ - struct MACH_HEADER_STRUCT header; - uint8_t* cmds; - uintptr_t entryPoint = 0, entryPointDylinker = 0; - struct MACH_HEADER_STRUCT* mappedHeader = NULL; - uintptr_t slide = 0; - uintptr_t mmapSize = 0; - bool pie = false; - uint32_t fat_offset; - - fat_offset = lseek(fd, 0, SEEK_CUR); - - if (read(fd, &header, sizeof(header)) != sizeof(header)) - { - fprintf(stderr, "Cannot read the mach header.\n"); - exit(1); - } - - cmds = (uint8_t*) malloc(header.sizeofcmds); - if (!cmds) - { - fprintf(stderr, "Cannot allocate %u bytes for loader commands.\n", header.sizeofcmds); - exit(1); - } - - if (read(fd, cmds, header.sizeofcmds) != header.sizeofcmds) - { - fprintf(stderr, "Cannot read loader commands.\n"); - exit(1); - } - - if ((header.filetype == MH_EXECUTE && header.flags & MH_PIE) || header.filetype == MH_DYLINKER) - { - uintptr_t base = -1; - - // Go through all SEGMENT_COMMAND commands to get the total continuous range required. - for (uint32_t i = 0, p = 0; i < header.ncmds; i++) - { - struct SEGMENT_STRUCT* seg = (struct SEGMENT_STRUCT*) &cmds[p]; - - // Load commands are always sorted, so this will get us the maximum address. - if (seg->cmd == SEGMENT_COMMAND) - { - if (base == -1) - { - base = seg->vmaddr; - if (base != 0 && header.filetype == MH_DYLINKER) - goto no_slide; - } - mmapSize = seg->vmaddr + seg->vmsize - base; - } - - p += seg->cmdsize; - } - - slide = (uintptr_t) mmap((void*) base, mmapSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_EXTRA, -1, 0); - if (slide == (uintptr_t)MAP_FAILED) - { - fprintf(stderr, "Cannot mmap anonymous memory range: %s", strerror(errno)); - exit(1); - } - - pie = true; - } -no_slide: - - for (uint32_t i = 0, p = 0; i < header.ncmds; i++) - { - struct load_command* lc; - - lc = (struct load_command*) &cmds[p]; - - switch (lc->cmd) - { - case SEGMENT_COMMAND: - { - struct SEGMENT_STRUCT* seg = (struct SEGMENT_STRUCT*) lc; - void* rv; - - if (memcmp(SEG_PAGEZERO, seg->segname, sizeof(SEG_PAGEZERO)) == 0) - { - // Let's skip pagezero and map a single page at address 0 elsewhere. - p += lc->cmdsize; - continue; - } - - if (seg->filesize < seg->vmsize) - { - if (slide != 0) - { - // Some segments' filesize != vmsize, thus this mprotect(). - if (mprotect((void*) (seg->vmaddr + slide), seg->vmsize, native_prot(seg->maxprot)) != 0) - { - fprintf(stderr, "Cannot mprotect for segment %s: %s\n", seg->segname, strerror(errno)); - exit(1); - } - } - else - { - size_t size = seg->vmsize - seg->filesize; - rv = mmap((void*) PAGE_ALIGN(seg->vmaddr + seg->vmsize - size), PAGE_ROUNDUP(size), native_prot(seg->maxprot), - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); - } - } - - if (seg->filesize > 0) - { - rv = mmap((void*) (seg->vmaddr + slide), seg->filesize, native_prot(seg->maxprot), - MAP_FIXED | MAP_PRIVATE, fd, seg->fileoff + fat_offset); - if (rv == (void*)MAP_FAILED) - { - fprintf(stderr, "Cannot mmap segment %s at %p: %s\n", seg->segname, (void*)(uintptr_t)seg->vmaddr, strerror(errno)); - exit(1); - } - - if (seg->fileoff == 0) - mappedHeader = (struct MACH_HEADER_STRUCT*) (seg->vmaddr + slide); - } - - if (strcmp(SEG_DATA, seg->segname) == 0) - { - // Look for section named __all_image_info for GDB integration - struct SECTION_STRUCT* sect = (struct SECTION_STRUCT*) (seg+1); - struct SECTION_STRUCT* end = (struct SECTION_STRUCT*) (&cmds[p + lc->cmdsize]); - - while (sect < end) - { - if (strncmp(sect->sectname, "__all_image_info", 16) == 0) - { - dyld_all_image_location = slide + sect->addr; - dyld_all_image_size = sect->size; -#ifdef GEN_64BIT - setup_gdb_notifications(slide, sect->addr); -#endif - break; - } - sect++; - } - } - break; - } - case LC_UNIXTHREAD: - { -#ifdef GEN_64BIT - entryPoint = ((uint64_t*) lc)[18]; -#endif -#ifdef GEN_32BIT - entryPoint = ((uint32_t*) lc)[14]; -#endif - entryPoint += slide; - break; - } - case LC_LOAD_DYLINKER: - { - struct dylinker_command* dy = (struct dylinker_command*) lc; - char path[4096]; - size_t length = dy->cmdsize - dy->name.offset; - - if (length > sizeof(path)-1) - { - fprintf(stderr, "Dynamic linker name too long: %zu\n", length); - exit(1); - } - - memcpy(path, ((char*) dy) + dy->name.offset, length); - path[length] = '\0'; - - apply_root_path(path); - -#ifdef GEN_64BIT - load(path, &entryPointDylinker, NULL, CPU_TYPE_X86_64, NULL); -#endif -#ifdef GEN_32BIT - load(path, &entryPointDylinker, NULL, CPU_TYPE_X86, NULL); -#endif - - break; - } - case LC_MAIN: - { - struct entry_point_command* ee = (struct entry_point_command*) lc; - if (ee->stacksize > stack_size) - stack_size = ee->stacksize; - break; - } - case LC_UUID: - { - if (header.filetype == MH_EXECUTE) - { - struct uuid_command* ue = (struct uuid_command*) lc; - memcpy(exe_uuid, ue->uuid, sizeof(exe_uuid)); - } - break; - } - } - - p += lc->cmdsize; - } - - free(cmds); - - if (entryPoint_out != NULL) - *entryPoint_out = entryPointDylinker ? entryPointDylinker : entryPoint; - if (mh_out != NULL) - *mh_out = (uintptr_t) mappedHeader; -} - - -#undef FUNCTION_NAME -#undef SEGMENT_STRUCT -#undef SEGMENT_COMMAND -#undef MACH_HEADER_STRUCT -#undef SECTION_STRUCT -#undef MAP_EXTRA - diff --git a/src/startup/mldr.c b/src/startup/mldr.c deleted file mode 100644 index 854f56d4b..000000000 --- a/src/startup/mldr.c +++ /dev/null @@ -1,570 +0,0 @@ -/* -This file is part of Darling. - -Copyright (C) 2017 Lubos Dolezel - -Darling is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Darling is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Darling. If not, see . -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "elfcalls.h" -#include "gdb.h" -#include "commpage.h" -#include "32in64.h" - -#define USE_32IN64 0 - -#ifndef PAGE_SIZE -# define PAGE_SIZE 4096 -#endif -#define PAGE_ALIGN(x) (x & ~(PAGE_SIZE-1)) -#define PAGE_ROUNDUP(x) (((((x)-1) / PAGE_SIZE)+1) * PAGE_SIZE) - -#define CPU_ARCH_ABI64 0x01000000 -#define CPU_TYPE_ANY ((cpu_type_t) -1) -#define CPU_TYPE_X86 ((cpu_type_t) 7) -#define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64) - -static const char* dyld_path = INSTALL_PREFIX "/libexec/usr/lib/dyld"; - -// The idea of mldr is to load dyld_path into memory and set up the stack -// as described in dyldStartup.S. -// After that, we pass control over to dyld. -// -// Additionally, mldr providers access to native platforms libdl.so APIs (ELF loader). - -#ifdef __x86_64__ -static void load64(int fd, uintptr_t* entryPoint_out, uintptr_t* mh_out); -static void reexec32(char** argv); -#endif -static void load32(int fd, uintptr_t* entryPoint_out, uintptr_t* mh_out); -static void load(const char* path, uintptr_t* entryPoint_out, uintptr_t* mh_out, cpu_type_t cpu, char** argv); -static int native_prot(int prot); -static void apply_root_path(char* path); -char* elfcalls_make(void); -static char* apple0_make(const char* filepath); -static void map_pagezero(void); - -// UUID of the main executable -uint8_t exe_uuid[16]; - -// Data for TASK_DYLD_INFO -uintptr_t dyld_all_image_location; -size_t dyld_all_image_size; - -#if USE_32IN64 -static void* setup_stack32(void* stack, int argc, const char** argv, const char** envp, const char** apple, uint64_t mh); - -static bool mode_32in64 = false; -#endif - -static uint32_t stack_size = 0; - -int main(int argc, char** argv, char** envp) -{ - uintptr_t entryPoint, mh; - void** sp; - int pushCount = 0; - const char* apple[3]; - char *filename, *p = NULL; - // sys_execve() passes the original file path appended to the mldr path in argv[0]. - if (argc > 0) - p = strchr(argv[0], '!'); - - if (argc <= 1) - { - if (p == NULL) { - fprintf(stderr, "mldr is part of Darling. It is not to be executed directly.\n"); - return 1; - } - else - { - fprintf(stderr, "mldr: warning: Executing with no argv[0]. Continuing anyway, but this is probably a bug.\n"); - } - } - - if (p != NULL) - { - filename = (char*) __builtin_alloca(strlen(argv[0])+1); - strcpy(filename, p + 1); - } - else - { - filename = (char*) __builtin_alloca(strlen(argv[1])+1); - strcpy(filename, argv[1]); - } - -#ifdef __i386__ - load(filename, &entryPoint, &mh, CPU_TYPE_X86, argv); // accept i386 only -#else - load(filename, &entryPoint, &mh, CPU_TYPE_ANY, argv); -#endif - - p = argv[0]; - // Update process name in ps output - for (int i = 1; i < argc; i++) - { - size_t len = strlen(argv[i]); - memmove(p, argv[i], len+1); - - argv[i-1] = p; - p += len+1; - } - - if (envp[0] != NULL) - memset(p, 0, envp[0]-p); - else - { - while (*p) - *p++ = '\0'; - } - argv[--argc] = NULL; - -#if __i386__ || __x86_64__ - if (getenv("BREAK_AFTER_LOAD") != NULL) - __asm__("int3"); -#endif - -#ifdef __x86_64__ -# define GETSP(ptr) __asm__ volatile("movq %%rsp, %0" : "=r"(ptr) ::) -# define JUMPX(pushCount, addr) __asm__ volatile("sub %1, %%rsp; jmpq *%0" :: "m"(addr), "r"(pushCount * sizeof(void*)) :) -#elif defined(__i386__) -# define GETSP(ptr) __asm__ volatile("movl %%esp, %0" : "=m"(ptr) ::) -# define JUMPX(pushCount, addr) __asm__ volatile("sub %1, %%esp; jmp *%0" :: "m"(addr), "r"(pushCount * sizeof(void*)) :) -#elif defined(__arm__) -# define GETSP(ptr) __asm__ volatile("mov %0, sp" : "=r"(ptr) ::) -# define JUMPX(pushCount, addr) __asm__ volatile("sub sp, %1; bx %0" :: "r"(addr), "r"(pushCount * sizeof(void*)) :) -#else -# error Unsupported platform! -#endif - - apple[0] = apple0_make(filename); - apple[1] = elfcalls_make(); - apple[2] = NULL; - - map_pagezero(); - -#if USE_32IN64 - if (!mode_32in64) -#endif - { - GETSP(sp); - sp--; - - for (int i = sizeof(apple)/sizeof(apple[0])-1; i >= 0; i--) - *(sp-(pushCount++)) = (void*) apple[i]; - - *(sp-(pushCount++)) = NULL; - for (int i = 0; environ[i] != NULL; i++) - *(sp-(pushCount++)) = environ[i]; - - *(sp-(pushCount++)) = NULL; - for (int i = argc-1; i >= 0; i--) - *(sp-(pushCount++)) = (void*) argv[i]; - - *(sp-(pushCount++)) = (void*) (uintptr_t)(argc); - *(sp-(pushCount++)) = (void*) mh; - - JUMPX(pushCount, entryPoint); - } -#if USE_32IN64 - else - { - uint32_t size = stack_size ? stack_size : 8*1024*1024; - size &= ~3u; - - sp = mmap(NULL, size, - PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_32BIT | MAP_ANONYMOUS, - -1, 0); - // stack guard page - mprotect(sp, PAGE_SIZE, PROT_NONE); - - // move to the top of the stack - sp += size/sizeof(void*) - 1; - - _64TO32_WITH_STACK(setup_stack32(sp, argc, (const char**) argv, (const char**) envp, apple, mh), entryPoint); - } -#endif - - __builtin_unreachable(); -} - -static char* copystring(void* stack, const char* str) -{ - size_t len = strlen(str); - char* pos = (char*) stack; - - pos -= len+1; - strcpy(pos, str); - - return pos; -} - -static size_t arraylen(const char** str) -{ - size_t len = 0; - while (str[len] != NULL) - len++; - return len; -} - -#if USE_32IN64 -void* setup_stack32(void* stack, int argc, const char** argv_in, const char** envp_in, const char** apple_in, uintptr_t mh) -{ - char **argv_new, **envp_new, **apple_new; - size_t size, apple_size; - uint32_t* stack_pointers; - - argv_new = (char**) __builtin_alloca((arraylen(argv_in) + 1) * sizeof(char*)); - for (int i = argc-1; i >= 0; i--) - stack = argv_new[i] = copystring(stack, argv_in[i]); - argv_new[argc] = NULL; - - size = arraylen(envp_in); - envp_new = (char**) __builtin_alloca((size + 1) * sizeof(char*)); - for (int i = size-1; i >= 0; i--) - stack = envp_new[i] = copystring(stack, envp_in[i]); - envp_new[size] = NULL; - - apple_size = arraylen(apple_in); - apple_new = (char**) __builtin_alloca((apple_size + 1) * sizeof(char*)); - for (int i = apple_size-1; i >= 0; i--) - stack = apple_new[i] = copystring(stack, apple_in[i]); - - stack_pointers = (uint32_t*) stack; - stack_pointers--; - - *stack_pointers-- = 0; - for (int i = apple_size-1; i >= 0; i--) - *stack_pointers-- = (uint32_t) apple_new[i]; - - *stack_pointers-- = 0; - for (int i = 0; envp_new[i] != NULL; i++) - *stack_pointers-- = (uint32_t) envp_new[i]; - - *stack_pointers-- = 0; - for (int i = argc-1; i >= 0; i--) - *stack_pointers-- = (uint32_t) argv_new[i]; - - *stack_pointers-- = argc; - *stack_pointers = (uint32_t) mh; - - return stack_pointers; -} -#endif - -static void parse_binprefs(uint32_t bprefs[4]) -{ - const char* bprefs_str; - - bprefs[0] = bprefs[1] = bprefs[2] = bprefs[3] = 0; - bprefs_str = getenv("__mldr_bprefs"); - - if (bprefs_str != NULL) - { - sscanf(bprefs_str, "%x,%x,%x,%x", &bprefs[0], &bprefs[1], &bprefs[2], &bprefs[3]); - unsetenv("__mldr_bprefs"); - } -} - -void load(const char* path, uintptr_t* entryPoint_out, uintptr_t* mh_out, cpu_type_t cpu_desired, char** argv) -{ - int fd; - uint32_t magic; - uint32_t bprefs[4]; - - fd = open(path, O_RDONLY); - if (fd == -1) - { - fprintf(stderr, "Cannot open %s: %s\n", path, strerror(errno)); - exit(1); - } - - // We need to read argv[1] and detect whether it's a 32 or 64-bit application. - // Then load the appropriate version of dyld from the fat file. - // In case the to-be-executed executable contains both, we prefer the 64-bit version, - // unless a special property has been passed to sys_posix_spawn() to force the 32-bit - // version. See posix_spawnattr_setbinpref_np(). - parse_binprefs(bprefs); - - if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) - { - fprintf(stderr, "Cannot read the file header of %s.\n", path); - exit(1); - } - - if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) - { -#ifndef __i386__ - if (mh_out) - commpage_setup(true); - - lseek(fd, 0, SEEK_SET); - load64(fd, entryPoint_out, mh_out); -#else - abort(); -#endif - } - else if (magic == MH_MAGIC || magic == MH_CIGAM) - { -#if !__x86_64__ || USE_32IN64 - if (mh_out) - commpage_setup(false); -#if __x86_64__ - mode_32in64 = true; -#endif - lseek(fd, 0, SEEK_SET); - load32(fd, entryPoint_out, mh_out); -#else - // Re-run self as mldr32 - reexec32(argv); -#endif - } - else if (magic == FAT_MAGIC || magic == FAT_CIGAM) - { - struct fat_header fhdr; - struct fat_arch best_arch; - const bool swap = magic == FAT_CIGAM; - - best_arch.cputype = CPU_TYPE_ANY; - - if (read(fd, &fhdr.nfat_arch, sizeof(fhdr.nfat_arch)) != sizeof(fhdr.nfat_arch)) - { - fprintf(stderr, "Cannot read the file header of %s.\n", path); - exit(1); - } - -#define SWAP32(x) x = __bswap_32(x) - - if (swap) - SWAP32(fhdr.nfat_arch); - - for (uint32_t i = 0; i < fhdr.nfat_arch; i++) - { - struct fat_arch arch; - - if (read(fd, &arch, sizeof(arch)) != sizeof(arch)) - { - fprintf(stderr, "Cannot read fat_arch header of %s.\n", path); - exit(1); - } - - if (swap) - { - SWAP32(arch.cputype); - SWAP32(arch.cpusubtype); - SWAP32(arch.offset); - SWAP32(arch.size); - SWAP32(arch.align); - } - - if (cpu_desired == CPU_TYPE_ANY) - { - // Find the best arch -#ifdef __x86_64__ - // Analyze binprefs used with posix_spawn() - for (int i = 0; i < sizeof(bprefs) / sizeof(bprefs[0]) && bprefs[i] != 0; i++) - { - if (arch.cputype == bprefs[i]) - { - memcpy(&best_arch, &arch, sizeof(arch)); - break; - } - } - - // Hope for x86-64, but also accept i386 - // TODO: x86_64h (Haswell) - if (arch.cputype == CPU_TYPE_X86_64) - { - memcpy(&best_arch, &arch, sizeof(arch)); - break; - } - else if (arch.cputype == CPU_TYPE_X86) - memcpy(&best_arch, &arch, sizeof(arch)); -#endif - } - else if (arch.cputype == cpu_desired) - { - memcpy(&best_arch, &arch, sizeof(arch)); - break; - } - } - - if (best_arch.cputype == CPU_TYPE_ANY) - { - fprintf(stderr, "No supported architecture found in fat %s.\n", path); - exit(1); - } - if (lseek(fd, best_arch.offset, SEEK_SET) == -1) - { - fprintf(stderr, "Cannot seek to selected arch in fat %s.\n", path); - exit(1); - } - - - if (mh_out) - commpage_setup(best_arch.cputype & CPU_ARCH_ABI64); - - if (best_arch.cputype & CPU_ARCH_ABI64) - { -#if !__i386__ - load64(fd, entryPoint_out, mh_out); -#else - abort(); -#endif - } - else - { -#if USE_32IN64 && __x86_64__ - mode_32in64 = true; -#endif -#if !USE_32IN64 && __x86_64__ - // Re-execute self as mldr32 - reexec32(argv); -#else - load32(fd, entryPoint_out, mh_out); -#endif - } - } - else - { - fprintf(stderr, "Unknown file format: %s.\n", path); - exit(1); - } - - close(fd); -} - -#ifdef __x86_64__ -#define GEN_64BIT -#include "loader.c" -#undef GEN_64BIT -#endif - -#define GEN_32BIT -#include "loader.c" -#undef GEN_32BIT - -int native_prot(int prot) -{ - int protOut = 0; - - if (prot & VM_PROT_READ) - protOut |= PROT_READ; - if (prot & VM_PROT_WRITE) - protOut |= PROT_WRITE; - if (prot & VM_PROT_EXECUTE) - protOut |= PROT_EXEC; - - return protOut; -} - -// Enable the use of DYLD_ROOT_PATH also for dyld itself. -// This is mainly used for testing. -void apply_root_path(char* path) -{ - const char* roots = getenv("DYLD_ROOT_PATH"); - char my_path[4096]; - const char *p, *next; - - if (!roots) - return; - - p = roots; - - do - { - next = strchr(p, ':'); - - if (next != NULL) - { - strncpy(my_path, p, next-p); - my_path[next-p] = '\0'; - next++; - } - else - { - strcpy(my_path, p); - } - - strcat(my_path, path); - - if (access(my_path, R_OK) == 0) - { - // We've found the desired path in one of the roots, switch to it - strcpy(path, my_path); - break; - } - } - while (next != NULL); -} - -char* apple0_make(const char* filepath) -{ - static char apple0[4096] = "executable_path="; - - if (filepath[0] == '/') - strcat(apple0, filepath); - else - { - char* path = realpath(filepath, NULL); - strcat(apple0, path); - free(path); - } - - return apple0; -} - -#ifdef __x86_64__ -static void reexec32(char** argv) -{ - char selfpath[1024]; - ssize_t len; - - len = readlink("/proc/self/exe", selfpath, sizeof(selfpath)-3); - if (len == -1) - { - perror("Cannot readlink /proc/self/exe"); - abort(); - } - - selfpath[len] = '\0'; - strcat(selfpath, "32"); - - execv(selfpath, argv); - - perror("Cannot re-execute as 32-bit process"); - abort(); -} -#endif - -static void map_pagezero(void) -{ - if (mmap(NULL, 4096, PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0) == MAP_FAILED) - fprintf(stderr, "Cannot mmap page zero, some apps may crash because of this (%s)\n", strerror(errno)); -}