/* * The file size of a mach-o file is limited to 32 bits; this is because * this is the limit on the kalloc() of enough bytes for a mach_header and * the contents of its sizeofcmds, which is currently constrained to 32 * bits in the file format itself. We read into the kernel buffer the * commands section, and then parse it in order to parse the mach-o file * format load_command segment(s). We are only interested in a subset of * the total set of possible commands. If "map"==VM_MAP_NULL or * "thread"==THREAD_NULL, do not make permament VM modifications, * just preflight the parse. */ static load_return_t parse_machfile( uint8_t *vp, struct mach_header *header, off_t file_offset, off_t macho_size, int depth, int64_t aslr_offset, int64_t dyld_aslr_offset, load_result_t *result ) { uint32_t ncmds; struct load_command *lcp; struct dylinker_command *dlp = 0; integer_t dlarchbits = 0; void * control; load_return_t ret = LOAD_SUCCESS; caddr_t addr; vm_size_t size,kl_size; size_t offset; size_t oldoffset; /* for overflow check */ int pass; size_t mach_header_sz = sizeof(struct mach_header); boolean_t abi64; boolean_t got_code_signatures = FALSE; int64_t slide = 0; if (header->magic == MH_MAGIC_64 || header->magic == MH_CIGAM_64) { mach_header_sz = sizeof(struct mach_header_64); } /* * Break infinite recursion */ if (depth > 6) { printf("parse_machfile 1: %s\n", load_to_string(LOAD_FAILURE)); return(LOAD_FAILURE); } depth++; /* * Check to see if right machine type. */ // this should be implemented by qemu somehow. /*if (((cpu_type_t)(header->cputype & ~CPU_ARCH_MASK) != (cpu_type() & ~CPU_ARCH_MASK)) || !grade_binary(header->cputype, header->cpusubtype & ~CPU_SUBTYPE_MASK)) return(LOAD_BADARCH);*/ abi64 = ((header->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64); switch (header->filetype) { case MH_OBJECT: case MH_EXECUTE: case MH_PRELOAD: if (depth != 1) { printf("parse_machfile 2: %s\n", load_to_string(LOAD_FAILURE)); return (LOAD_FAILURE); } break; case MH_FVMLIB: case MH_DYLIB: if (depth == 1) { printf("parse_machfile 2: %s\n", load_to_string(LOAD_FAILURE)); return (LOAD_FAILURE); } break; case MH_DYLINKER: if (depth != 2) { printf("parse_machfile 3: %s\n", load_to_string(LOAD_FAILURE)); return (LOAD_FAILURE); } break; default: printf("parse_machfile 4: %s, header->filetype = %d\n", load_to_string(LOAD_FAILURE), header->filetype); return (LOAD_FAILURE); } /* * Map portion that must be accessible directly into * kernel's map. */ if ((off_t)(mach_header_sz + header->sizeofcmds) > macho_size) { printf("parse_machfile 5: %s header->sizeofcmds: %d macho_size %d\n", load_to_string(LOAD_BADMACHO), header->sizeofcmds, macho_size); return(LOAD_BADMACHO); } /* * Round size of Mach-O commands up to page boundry. */ size = round_page(mach_header_sz + header->sizeofcmds); if (size <= 0) { printf("parse_machfile 6: %s\n", load_to_string(LOAD_BADMACHO)); return(LOAD_BADMACHO); } /* * Map the load commands into kernel memory. */ addr = 0; kl_size = size; addr = (caddr_t)(vp); if (addr == NULL) { printf("parse_machfile 7: %s\n", load_to_string(LOAD_NOSPACE)); return(LOAD_NOSPACE); } /* * For PIE and dyld, slide everything by the ASLR offset. */ if ((header->flags & MH_PIE) || (header->filetype == MH_DYLINKER)) { slide = aslr_offset; } /* * Scan through the commands, processing each one as necessary. * We parse in three passes through the headers: * 1: thread state, uuid, code signature * 2: segments * 3: dyld, encryption, check entry point */ for (pass = 1; pass <= 3; pass++) { /* * Check that the entry point is contained in an executable segments */ if ((pass == 3) && (result->validentry == 0)) { ret = LOAD_FAILURE; break; } /* * Loop through each of the load_commands indicated by the * Mach-O header; if an absurd value is provided, we just * run off the end of the reserved section by incrementing * the offset too far, so we are implicitly fail-safe. */ offset = mach_header_sz; ncmds = header->ncmds; while (ncmds--) { /* * Get a pointer to the command. */ lcp = (struct load_command *)(addr + offset); oldoffset = offset; offset += lcp->cmdsize; /* * Perform prevalidation of the struct load_command * before we attempt to use its contents. Invalid * values are ones which result in an overflow, or * which can not possibly be valid commands, or which * straddle or exist past the reserved section at the * start of the image. */ if (oldoffset > offset || lcp->cmdsize < sizeof(struct load_command) || offset > header->sizeofcmds + mach_header_sz) { ret = LOAD_BADMACHO; break; } /* * Act on struct load_command's for which kernel * intervention is required. */ printf("Command: %s\n", command_to_string(lcp->cmd)); switch(lcp->cmd) { case LC_SEGMENT: if (pass != 2) break; if (abi64) { /* * Having an LC_SEGMENT command for the * wrong ABI is invalid <rdar://problem/11021230> */ ret = LOAD_BADMACHO; break; } ret = load_segment(lcp, header->filetype, control, file_offset, macho_size, vp, slide, result); break; case LC_SEGMENT_64: if (pass != 2) break; if (!abi64) { /* * Having an LC_SEGMENT_64 command for the * wrong ABI is invalid <rdar://problem/11021230> */ ret = LOAD_BADMACHO; break; } ret = load_segment(lcp, header->filetype, control, file_offset, macho_size, vp, slide, result); break; case LC_UNIXTHREAD: if (pass != 1) break; ret = load_unixthread( (struct thread_command *) lcp, result); break; case LC_MAIN: if (pass != 1) break; if (depth != 1) break; ret = load_main( (struct entry_point_command *) lcp, result); break; case LC_LOAD_DYLINKER: if (pass != 3) break; if ((depth == 1) && (dlp == 0)) { dlp = (struct dylinker_command *)lcp; dlarchbits = (header->cputype & CPU_ARCH_MASK); } else { ret = LOAD_FAILURE; } break; case LC_UUID: if (pass == 1 && depth == 1) { ret = load_uuid((struct uuid_command *) lcp, (char *)addr + mach_header_sz + header->sizeofcmds, result); } break; case LC_CODE_SIGNATURE: /* CODE SIGNING */ if (pass != 1) break; /* pager -> uip -> load signatures & store in uip set VM object "signed_pages" */ /*ret = load_code_signature( (struct linkedit_data_command *) lcp, vp, file_offset, macho_size, header->cputype, result);*/ if (ret != LOAD_SUCCESS) { printf("proc: load code signature error %d ", ret); ret = LOAD_SUCCESS; /* ignore error */ } else { got_code_signatures = TRUE; } break; #if CONFIG_CODE_DECRYPTION case LC_ENCRYPTION_INFO: case LC_ENCRYPTION_INFO_64: if (pass != 3) break; ret = set_code_unprotect( (struct encryption_info_command *) lcp, addr, map, slide, vp, header->cputype, header->cpusubtype); if (ret != LOAD_SUCCESS) { printf("proc %d: set_code_unprotect() error %d " "for file \"%s\"\n", p->p_pid, ret, vp->v_name); /* * Don't let the app run if it's * encrypted but we failed to set up the * decrypter. If the keys are missing it will * return LOAD_DECRYPTFAIL. */ if (ret == LOAD_DECRYPTFAIL) { /* failed to load due to missing FP keys */ proc_lock(p); p->p_lflag |= P_LTERM_DECRYPTFAIL; proc_unlock(p); } psignal(p, SIGKILL); } break; #endif default: /* Other commands are ignored by the kernel */ ret = LOAD_SUCCESS; break; } printf("parse_machfile 9: ret %s\n", load_to_string(ret)); if (ret != LOAD_SUCCESS) break; } if (ret != LOAD_SUCCESS) break; } if (ret == LOAD_SUCCESS) { if (! got_code_signatures) { //struct cs_blob *blob; /* no embedded signatures: look for detached ones */ //blob = ubc_cs_blob_get(vp, -1, file_offset); //if (blob != NULL) { //unsigned int cs_flag_data = blob->csb_flags; //if(0 != ubc_cs_generation_check(vp)) { // if (0 != ubc_cs_blob_revalidate(vp, blob)) { // /* clear out the flag data if revalidation fails */ // cs_flag_data = 0; // result->csflags &= ~CS_VALID; // } //} /* get flags to be applied to the process */ //result->csflags |= cs_flag_data; //} } /* Make sure if we need dyld, we got it */ if (result->needs_dynlinker && !dlp) { ret = LOAD_FAILURE; } if ((ret == LOAD_SUCCESS) && (dlp != 0)) { /* * load the dylinker, and slide it by the independent DYLD ASLR * offset regardless of the PIE-ness of the main binary. */ ret = load_dylinker(dlp, dlarchbits, depth, dyld_aslr_offset, result); } if((ret == LOAD_SUCCESS) && (depth == 1)) { if (result->thread_count == 0) { ret = LOAD_FAILURE; } } } printf("parse_machfile 8: %s\n", load_to_string(ret)); return(ret); }
/* Loads a Mach-O executable into memory, along with any threads, stacks, and dylinker. Returns 0 on success, -1 on any failure. fd[offset..offset+size) is a Mach-O thin file. filetype is MH_EXECUTE or MH_DYLINKER. The mapped but empty stack is returned in *out_stack. The executable's Mach headers are returned in *out_text. The executable's entry point is returned in *out_entry. The dylinker's entry point (if any) is returned in *out_linker_entry. GrP fixme need to return whether dylinker was found - stack layout is different */ static int load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, const char *filename, vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry) { struct MACH_HEADER mh; vki_uint8_t *headers; vki_uint8_t *headers_end; struct load_command *lc; struct load_command *lcend; struct SEGMENT_COMMAND *segcmd; struct thread_command *threadcmd; struct dylinker_command *dycmd; int err; SysRes res; vki_size_t len; vki_uint8_t *stack_start = NULL; // allocated thread stack (hot end) vki_uint8_t *stack_end = NULL; // allocated thread stack (cold end) vki_uint8_t *entry = NULL; // static entry point vki_uint8_t *text = NULL; // start of text segment (i.e. the mach headers) vki_uint8_t *linker_entry = NULL; // dylinker entry point // Read Mach-O header if (sizeof(mh) > size) { print("bad executable (no Mach-O header)\n"); } res = VG_(pread)(fd, &mh, sizeof(mh), offset); if (sr_isError(res) || sr_Res(res) != sizeof(mh)) { print("bad executable (no Mach-O header)\n"); return -1; } // Sanity-check the header itself if (mh.magic != MAGIC) { print("bad executable (no Mach-O magic)\n"); return -1; } if (mh.filetype != filetype) { // expecting MH_EXECUTE or MH_DYLINKER print("bad executable (wrong file type)\n"); return -1; } // Map all headers into memory len = sizeof(mh) + mh.sizeofcmds; if (len > size) { print("bad executable (missing load commands)\n"); return -1; } headers = VG_(malloc)("ume.macho.headers", len); res = VG_(pread)(fd, headers, len, offset); if (sr_isError(res)) { print("couldn't read load commands from executable\n"); return -1; } headers_end = headers + len; // Map some segments into client memory: // LC_SEGMENT (text, data, etc) // UNIXSTACK (stack) // LOAD_DYLINKER (dyld) lcend = (struct load_command *)(headers + mh.sizeofcmds + sizeof(mh)); for (lc = (struct load_command *)(headers + sizeof(mh)); lc < lcend; lc = (struct load_command *)(lc->cmdsize + (vki_uint8_t *)lc)) { if ((vki_uint8_t *)lc < headers || lc->cmdsize+(vki_uint8_t *)lc > headers_end) { print("bad executable (invalid load commands)\n"); return -1; } switch (lc->cmd) { case LC_SEGMENT_CMD: if (lc->cmdsize < sizeof(struct SEGMENT_COMMAND)) { print("bad executable (invalid load commands)\n"); return -1; } segcmd = (struct SEGMENT_COMMAND *)lc; err = load_segment(fd, offset, size, &text, &stack_start, segcmd, filename); if (err) return -1; break; case LC_UNIXTHREAD: if (stack_end || entry) { print("bad executable (multiple thread commands)\n"); return -1; } if (lc->cmdsize < sizeof(struct thread_command)) { print("bad executable (invalid load commands)\n"); return -1; } threadcmd = (struct thread_command *)lc; err = load_unixthread(&stack_start, &stack_end, &entry, threadcmd); if (err) return -1; break; case LC_LOAD_DYLINKER: if (filetype == MH_DYLINKER) { print("bad executable (dylinker needs a dylinker)\n"); return -1; } if (linker_entry) { print("bad executable (multiple dylinker commands)\n"); } if (lc->cmdsize < sizeof(struct dylinker_command)) { print("bad executable (invalid load commands)\n"); return -1; } dycmd = (struct dylinker_command *)lc; err = load_dylinker(&linker_entry, dycmd); if (err) return -1; break; case LC_THREAD: if (filetype == MH_EXECUTE) { print("bad executable (stackless thread)\n"); return -1; } if (stack_end || entry) { print("bad executable (multiple thread commands)\n"); return -1; } if (lc->cmdsize < sizeof(struct thread_command)) { print("bad executable (invalid load commands)\n"); return -1; } threadcmd = (struct thread_command *)lc; err = load_thread(&entry, threadcmd); if (err) return -1; break; default: break; } } // Done with the headers VG_(free)(headers); if (filetype == MH_EXECUTE) { // Verify the necessary pieces for an executable: // a stack // a text segment // an entry point (static or linker) if (!stack_end || !stack_start) { print("bad executable (no stack)\n"); return -1; } if (!text) { print("bad executable (no text segment)\n"); return -1; } if (!entry && !linker_entry) { print("bad executable (no entry point)\n"); return -1; } } else if (filetype == MH_DYLINKER) { // Verify the necessary pieces for a dylinker: // an entry point if (!entry) { print("bad executable (no entry point)\n"); return -1; } } if (out_stack_start) *out_stack_start = stack_start; if (out_stack_end) *out_stack_end = stack_end; if (out_text) *out_text = text; if (out_entry) *out_entry = entry; if (out_linker_entry) *out_linker_entry = linker_entry; return 0; }
/* * The file size of a mach-o file is limited to 32 bits; this is because * this is the limit on the kalloc() of enough bytes for a mach_header and * the contents of its sizeofcmds, which is currently constrained to 32 * bits in the file format itself. We read into the kernel buffer the * commands section, and then parse it in order to parse the mach-o file * format load_command segment(s). We are only interested in a subset of * the total set of possible commands. If "map"==VM_MAP_NULL or * "thread"==THREAD_NULL, do not make permament VM modifications, * just preflight the parse. */ static load_return_t parse_machfile( struct vnode *vp, vm_map_t map, thread_t thread, struct mach_header *header, off_t file_offset, off_t macho_size, int depth, int64_t aslr_offset, load_result_t *result ) { uint32_t ncmds; struct load_command *lcp; struct dylinker_command *dlp = 0; struct uuid_command *uulp = 0; integer_t dlarchbits = 0; void * control; load_return_t ret = LOAD_SUCCESS; caddr_t addr; void * kl_addr; vm_size_t size,kl_size; size_t offset; size_t oldoffset; /* for overflow check */ int pass; proc_t p = current_proc(); /* XXXX */ int error; int resid=0; size_t mach_header_sz = sizeof(struct mach_header); boolean_t abi64; boolean_t got_code_signatures = FALSE; int64_t slide = 0; if (header->magic == MH_MAGIC_64 || header->magic == MH_CIGAM_64) { mach_header_sz = sizeof(struct mach_header_64); } /* * Break infinite recursion */ if (depth > 6) { return(LOAD_FAILURE); } depth++; /* * Check to see if right machine type. */ if (((cpu_type_t)(header->cputype & ~CPU_ARCH_MASK) != cpu_type()) || !grade_binary(header->cputype, header->cpusubtype & ~CPU_SUBTYPE_MASK)) return(LOAD_BADARCH); abi64 = ((header->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64); switch (header->filetype) { case MH_OBJECT: case MH_EXECUTE: case MH_PRELOAD: if (depth != 1) { return (LOAD_FAILURE); } break; case MH_FVMLIB: case MH_DYLIB: if (depth == 1) { return (LOAD_FAILURE); } break; case MH_DYLINKER: if (depth != 2) { return (LOAD_FAILURE); } break; default: return (LOAD_FAILURE); } /* * Get the pager for the file. */ control = ubc_getobject(vp, UBC_FLAGS_NONE); /* * Map portion that must be accessible directly into * kernel's map. */ if ((off_t)(mach_header_sz + header->sizeofcmds) > macho_size) return(LOAD_BADMACHO); /* * Round size of Mach-O commands up to page boundry. */ size = round_page(mach_header_sz + header->sizeofcmds); if (size <= 0) return(LOAD_BADMACHO); /* * Map the load commands into kernel memory. */ addr = 0; kl_size = size; kl_addr = kalloc(size); addr = (caddr_t)kl_addr; if (addr == NULL) return(LOAD_NOSPACE); error = vn_rdwr(UIO_READ, vp, addr, size, file_offset, UIO_SYSSPACE, 0, kauth_cred_get(), &resid, p); if (error) { if (kl_addr ) kfree(kl_addr, kl_size); return(LOAD_IOERROR); } /* * For PIE and dyld, slide everything by the ASLR offset. */ aslr_offset = 0; if ((header->flags & MH_PIE) || (header->filetype == MH_DYLINKER)) { slide = aslr_offset; } /* * Scan through the commands, processing each one as necessary. */ for (pass = 1; pass <= 3; pass++) { /* * Check that the entry point is contained in an executable segments */ if ((pass == 3) && (result->validentry == 0)) { thread_state_initialize(thread); ret = LOAD_FAILURE; break; } /* * Loop through each of the load_commands indicated by the * Mach-O header; if an absurd value is provided, we just * run off the end of the reserved section by incrementing * the offset too far, so we are implicitly fail-safe. */ offset = mach_header_sz; ncmds = header->ncmds; while (ncmds--) { /* * Get a pointer to the command. */ lcp = (struct load_command *)(addr + offset); oldoffset = offset; offset += lcp->cmdsize; /* * Perform prevalidation of the struct load_command * before we attempt to use its contents. Invalid * values are ones which result in an overflow, or * which can not possibly be valid commands, or which * straddle or exist past the reserved section at the * start of the image. */ if (oldoffset > offset || lcp->cmdsize < sizeof(struct load_command) || offset > header->sizeofcmds + mach_header_sz) { ret = LOAD_BADMACHO; break; } /* * Act on struct load_command's for which kernel * intervention is required. */ switch(lcp->cmd) { case LC_SEGMENT: case LC_SEGMENT_64: if (pass != 2) break; ret = load_segment(lcp, header->filetype, control, file_offset, macho_size, vp, map, slide, result); break; case LC_UNIXTHREAD: if (pass != 1) break; ret = load_unixthread( (struct thread_command *) lcp, thread, slide, result); break; case LC_MAIN: if (pass != 1) break; if (depth != 1) break; ret = load_main( (struct entry_point_command *) lcp, thread, slide, result); break; case LC_LOAD_DYLINKER: if (pass != 3) break; if ((depth == 1) && (dlp == 0)) { dlp = (struct dylinker_command *)lcp; dlarchbits = (header->cputype & CPU_ARCH_MASK); } else { ret = LOAD_FAILURE; } break; case LC_UUID: if (pass == 1 && depth == 1) { uulp = (struct uuid_command *)lcp; memcpy(&result->uuid[0], &uulp->uuid[0], sizeof(result->uuid)); } break; case LC_CODE_SIGNATURE: /* CODE SIGNING */ if (pass != 1) break; /* pager -> uip -> load signatures & store in uip set VM object "signed_pages" */ ret = load_code_signature( (struct linkedit_data_command *) lcp, vp, file_offset, macho_size, header->cputype, (depth == 1) ? result : NULL); if (ret != LOAD_SUCCESS) { printf("proc %d: load code signature error %d " "for file \"%s\"\n", p->p_pid, ret, vp->v_name); ret = LOAD_SUCCESS; /* ignore error */ } else { got_code_signatures = TRUE; } break; #if CONFIG_CODE_DECRYPTION #ifndef __arm__ case LC_ENCRYPTION_INFO: if (pass != 3) break; ret = set_code_unprotect( (struct encryption_info_command *) lcp, addr, map, slide, vp); if (ret != LOAD_SUCCESS) { printf("proc %d: set_code_unprotect() error %d " "for file \"%s\"\n", p->p_pid, ret, vp->v_name); /* Don't let the app run if it's * encrypted but we failed to set up the * decrypter */ psignal(p, SIGKILL); } break; #endif #endif default: /* Other commands are ignored by the kernel */ ret = LOAD_SUCCESS; break; } if (ret != LOAD_SUCCESS) break; } if (ret != LOAD_SUCCESS) break; } if (ret == LOAD_SUCCESS) { if (! got_code_signatures) { struct cs_blob *blob; /* no embedded signatures: look for detached ones */ blob = ubc_cs_blob_get(vp, -1, file_offset); if (blob != NULL) { /* get flags to be applied to the process */ result->csflags |= blob->csb_flags; } } /* Make sure if we need dyld, we got it */ if (result->needs_dynlinker && !dlp) { ret = LOAD_FAILURE; } if ((ret == LOAD_SUCCESS) && (dlp != 0)) { /* load the dylinker, and always slide it by the ASLR * offset regardless of PIE */ ret = load_dylinker(dlp, dlarchbits, map, thread, depth, aslr_offset, result); } if((ret == LOAD_SUCCESS) && (depth == 1)) { if (result->thread_count == 0) { ret = LOAD_FAILURE; } } } if (kl_addr ) kfree(kl_addr, kl_size); return(ret); }
/* * The file size of a mach-o file is limited to 32 bits; this is because * this is the limit on the kalloc() of enough bytes for a mach_header and * the contents of its sizeofcmds, which is currently constrained to 32 * bits in the file format itself. We read into the kernel buffer the * commands section, and then parse it in order to parse the mach-o file * format load_command segment(s). We are only interested in a subset of * the total set of possible commands. */ static load_return_t parse_machfile( struct vnode *vp, vm_map_t map, thread_t thread, struct mach_header *header, off_t file_offset, off_t macho_size, int depth, load_result_t *result ) { uint32_t ncmds; struct load_command *lcp; struct dylinker_command *dlp = 0; integer_t dlarchbits = 0; void * pager; load_return_t ret = LOAD_SUCCESS; caddr_t addr; void * kl_addr; vm_size_t size,kl_size; size_t offset; size_t oldoffset; /* for overflow check */ int pass; proc_t p = current_proc(); /* XXXX */ int error; int resid=0; task_t task; size_t mach_header_sz = sizeof(struct mach_header); boolean_t abi64; boolean_t got_code_signatures = FALSE; if (header->magic == MH_MAGIC_64 || header->magic == MH_CIGAM_64) { mach_header_sz = sizeof(struct mach_header_64); } /* * Break infinite recursion */ if (depth > 6) { return(LOAD_FAILURE); } task = (task_t)get_threadtask(thread); depth++; /* * Check to see if right machine type. */ if (((cpu_type_t)(header->cputype & ~CPU_ARCH_MASK) != cpu_type()) || !grade_binary(header->cputype, header->cpusubtype & ~CPU_SUBTYPE_MASK)) return(LOAD_BADARCH); abi64 = ((header->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64); switch (header->filetype) { case MH_OBJECT: case MH_EXECUTE: case MH_PRELOAD: if (depth != 1) { return (LOAD_FAILURE); } break; case MH_FVMLIB: case MH_DYLIB: if (depth == 1) { return (LOAD_FAILURE); } break; case MH_DYLINKER: if (depth != 2) { return (LOAD_FAILURE); } break; default: return (LOAD_FAILURE); } /* * Get the pager for the file. */ pager = (void *) ubc_getpager(vp); /* * Map portion that must be accessible directly into * kernel's map. */ if ((mach_header_sz + header->sizeofcmds) > macho_size) return(LOAD_BADMACHO); /* * Round size of Mach-O commands up to page boundry. */ size = round_page(mach_header_sz + header->sizeofcmds); if (size <= 0) return(LOAD_BADMACHO); /* * Map the load commands into kernel memory. */ addr = 0; kl_size = size; kl_addr = kalloc(size); addr = (caddr_t)kl_addr; if (addr == NULL) return(LOAD_NOSPACE); error = vn_rdwr(UIO_READ, vp, addr, size, file_offset, UIO_SYSSPACE32, 0, kauth_cred_get(), &resid, p); if (error) { if (kl_addr ) kfree(kl_addr, kl_size); return(LOAD_IOERROR); } /* (void)ubc_map(vp, PROT_EXEC); */ /* NOT HERE */ /* * Scan through the commands, processing each one as necessary. */ for (pass = 1; pass <= 2; pass++) { /* * Loop through each of the load_commands indicated by the * Mach-O header; if an absurd value is provided, we just * run off the end of the reserved section by incrementing * the offset too far, so we are implicitly fail-safe. */ offset = mach_header_sz; ncmds = header->ncmds; while (ncmds--) { /* * Get a pointer to the command. */ lcp = (struct load_command *)(addr + offset); oldoffset = offset; offset += lcp->cmdsize; /* * Perform prevalidation of the struct load_command * before we attempt to use its contents. Invalid * values are ones which result in an overflow, or * which can not possibly be valid commands, or which * straddle or exist past the reserved section at the * start of the image. */ if (oldoffset > offset || lcp->cmdsize < sizeof(struct load_command) || offset > header->sizeofcmds + mach_header_sz) { ret = LOAD_BADMACHO; break; } /* * Act on struct load_command's for which kernel * intervention is required. */ switch(lcp->cmd) { case LC_SEGMENT_64: if (pass != 1) break; ret = load_segment_64( (struct segment_command_64 *)lcp, pager, file_offset, macho_size, ubc_getsize(vp), map, result); break; case LC_SEGMENT: if (pass != 1) break; ret = load_segment( (struct segment_command *) lcp, pager, file_offset, macho_size, ubc_getsize(vp), map, result); break; case LC_THREAD: if (pass != 2) break; ret = load_thread((struct thread_command *)lcp, thread, result); break; case LC_UNIXTHREAD: if (pass != 2) break; ret = load_unixthread( (struct thread_command *) lcp, thread, result); break; case LC_LOAD_DYLINKER: if (pass != 2) break; if ((depth == 1) && (dlp == 0)) { dlp = (struct dylinker_command *)lcp; dlarchbits = (header->cputype & CPU_ARCH_MASK); } else { ret = LOAD_FAILURE; } break; case LC_CODE_SIGNATURE: /* CODE SIGNING */ if (pass != 2) break; /* pager -> uip -> load signatures & store in uip set VM object "signed_pages" */ ret = load_code_signature( (struct linkedit_data_command *) lcp, vp, file_offset, macho_size, header->cputype, (depth == 1) ? result : NULL); if (ret != LOAD_SUCCESS) { printf("proc %d: load code signature error %d " "for file \"%s\"\n", p->p_pid, ret, vp->v_name); ret = LOAD_SUCCESS; /* ignore error */ } else { got_code_signatures = TRUE; } break; default: /* Other commands are ignored by the kernel */ ret = LOAD_SUCCESS; break; } if (ret != LOAD_SUCCESS) break; } if (ret != LOAD_SUCCESS) break; } if (ret == LOAD_SUCCESS) { if (! got_code_signatures) { struct cs_blob *blob; /* no embedded signatures: look for detached ones */ blob = ubc_cs_blob_get(vp, -1, file_offset); if (blob != NULL) { /* get flags to be applied to the process */ result->csflags |= blob->csb_flags; } } if (dlp != 0) ret = load_dylinker(dlp, dlarchbits, map, thread, depth, result, abi64); if(depth == 1) { if (result->thread_count == 0) { ret = LOAD_FAILURE; } else if ( abi64 ) { #ifdef __ppc__ /* Map in 64-bit commpage */ /* LP64todo - make this clean */ /* * PPC51: ppc64 is limited to 51-bit addresses. * Memory above that limit is handled specially * at the pmap level. */ pmap_map_sharedpage(current_task(), get_map_pmap(map)); #endif /* __ppc__ */ } } } if (kl_addr ) kfree(kl_addr, kl_size); if (ret == LOAD_SUCCESS) (void)ubc_map(vp, PROT_READ | PROT_EXEC); return(ret); }