KXKextManagerError PreLink(KXKextManagerRef theKextManager, CFDictionaryRef kextDict, const char * kernelCacheFilename, const char * kernel_file_name, const char * platform_name, const char * root_path, CFSetRef kernel_requests, Boolean all_plists, const NXArchInfo * arch, int verbose_level, Boolean debug_mode) { KXKextManagerError result = kKXKextManagerErrorFileAccess; CFIndex kexts_count, i; KXKextRef * kexts = NULL; // must free KXKextRef theKext = NULL; // don't release char symbol_dir[1 + strlen(TEMP_DIR)]; const char * temp_file = "cache.out"; int outfd = -1, curwd = -1; CFBundleRef kextBundle = NULL; // don't release CFMutableArrayRef moduleList; CFMutableDictionaryRef infoDict; vm_offset_t nextKernelVM; Boolean use_existing, kernel_swapped, includeInfo; vm_offset_t kernel_file, kernel_map; off_t kernel_size; vm_size_t kernel_file_size, bytes, totalBytes; vm_size_t totalModuleBytes, totalInfoBytes; vm_size_t totalSymbolBytes, totalSymbolSetBytes, totalSymbolDiscardedBytes; vm_size_t remainingModuleBytes, fileoffset, vmoffset, tailoffset; CFIndex idx, ncmds, cmd; IOReturn err; struct segment_command * seg; struct segment_command * prelinkseg; struct section * prelinksects; struct PrelinkState { kmod_info_t modules[1]; }; struct PrelinkState prelink_state_init; struct PrelinkState * prelink_state; vm_size_t prelink_size; int * prelink_dependencies; vm_size_t prelink_dependencies_size; kmod_info_t * lastInfo; struct FileInfo { vm_offset_t mapped; vm_size_t mappedSize; vm_offset_t symtaboffset; vm_offset_t symbolsetoffset; vm_size_t symtabsize; vm_size_t symtabdiscarded; CFStringRef key; KXKextRef kext; Boolean code; Boolean swapped; }; struct FileInfo * files = NULL; // -- symbol_dir[0] = 0; moduleList = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); if (kKXKextManagerErrorNone != (err = readFile(kernel_file_name, &kernel_file, &kernel_file_size))) goto finish; find_arch( (u_int8_t **) &kernel_map, &kernel_size, arch->cputype, arch->cpusubtype, (u_int8_t *) kernel_file, kernel_file_size); if (!kernel_size) { fprintf(stderr, "can't find architecture %s in %s\n", arch->name, kernel_file_name); err = kKXKextManagerErrorLinkLoad; goto finish; } if (arch->cputype != CPU_TYPE_ANY) kld_set_architecture(arch); kernel_swapped = kld_macho_swap((struct mach_header *)kernel_map); ncmds = ((struct mach_header *)kernel_map)->ncmds; seg = (struct segment_command *)(((struct mach_header *)kernel_map) + 1); for (cmd = 0; cmd < ncmds; cmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + seg->cmdsize)) { if (LC_SEGMENT != seg->cmd) continue; if (strcmp("__PRELINK", seg->segname)) continue; break; } if (cmd >= ncmds) { fprintf(stderr, "no __PRELINK segment in %s\n", kernel_file_name); err = kKXKextManagerErrorLinkLoad; goto finish; } prelinkseg = seg; prelinksects = (struct section *) (prelinkseg + 1); if ((prelinkseg->nsects != 3) || (strcmp("__text", prelinksects[0].sectname)) || (strcmp("__symtab", prelinksects[1].sectname)) || (strcmp("__info", prelinksects[2].sectname))) { fprintf(stderr, "unexpected __PRELINK sections in %s\n", kernel_file_name); err = kKXKextManagerErrorLinkLoad; goto finish; } if (!prelinkseg->fileoff) prelinkseg->fileoff = prelinksects[0].offset; strcpy(symbol_dir, TEMP_DIR); mktemp(symbol_dir); if (0 != mkdir(symbol_dir, 0755)) { fprintf(stderr, "mkdir(%s) failed: %s\n", symbol_dir, strerror(errno)); symbol_dir[0] = 0; err = kKXKextManagerErrorFileAccess; goto finish; } curwd = open(".", O_RDONLY, 0); if (0 != chdir(symbol_dir)) { perror("chdir"); err = kKXKextManagerErrorFileAccess; goto finish; } use_existing = false; if (!use_existing) { int fd; bzero(&prelink_state_init, sizeof(prelink_state_init)); prelink_state_init.modules[0].address = prelinkseg->vmaddr; fd = open("prelinkstate", O_WRONLY|O_CREAT|O_TRUNC, 0755); if (-1 == fd) { perror("create prelinkstate failed"); err = kKXKextManagerErrorFileAccess; goto finish; } err = writeFile(fd, &prelink_state_init, sizeof(prelink_state_init)); close(fd); if (kKXKextManagerErrorNone != err) goto finish; } /* Prepare to iterate over the kexts in the dictionary. */ kexts_count = CFDictionaryGetCount(kextDict); kexts = (KXKextRef *) calloc(kexts_count, sizeof(KXKextRef)); if (!kexts) { fprintf(stderr, "memory allocation failure\n"); err = kKXKextManagerErrorNoMemory; goto finish; } CFDictionaryGetKeysAndValues(kextDict, (const void **)NULL, (const void **)kexts); for (i = 0; i < kexts_count; i++) { Boolean linkit; theKext = (KXKextRef) kexts[i]; linkit = KXKextGetDeclaresExecutable(theKext) && (kextBundle = KXKextGetBundle(theKext)); if (linkit && kernel_requests) { CFStringRef bundleIdentifier = CFBundleGetIdentifier(kextBundle); linkit = (bundleIdentifier && CFSetContainsValue(kernel_requests, bundleIdentifier)); } if (linkit) { result = _KXKextManagerPrepareKextForLoading( theKextManager, theKext, NULL /*kext_name*/, FALSE /*check_loaded_for_dependencies*/, FALSE /*do_load*/, NULL /*inauthenticKexts*/); if (!use_existing && (result == kKXKextManagerErrorNone)) { result = _KXKextManagerLoadKextUsingOptions( theKextManager, theKext, NULL /*kext_name*/, kernel_file_name, NULL /*patch_dir*/, symbol_dir, kKXKextManagerLoadPrelink /*load_options*/, FALSE /*do_start_kmod*/, 0 /*interactive_level*/, FALSE /*ask_overwrite_symbols*/, FALSE /*overwrite_symbols*/, FALSE /*get_addrs_from_kernel*/, 0 /*num_addresses*/, NULL /*addresses*/); } if ((result != kKXKextManagerErrorNone) && (verbose_level > 0)) { const char * kext_path = NULL; // must free kext_path = _KXKextCopyCanonicalPathnameAsCString(theKext); if (kext_path) { fprintf(stderr, kext_path); free((char *)kext_path); } fprintf(stderr, " error 0x%x\n", result); } } } { struct module_header { struct mach_header h; struct segment_command seg[1]; }; struct module_header * header; int num_modules; if (kKXKextManagerErrorNone != (err = readFile("prelinkstate", (vm_offset_t *) &prelink_state, &prelink_size))) goto finish; if (kKXKextManagerErrorNone != (err = readFile("prelinkdependencies", (vm_offset_t *) &prelink_dependencies, &prelink_dependencies_size))) goto finish; num_modules = prelink_state->modules[0].id; nextKernelVM = prelink_state->modules[0].address; if (!num_modules || (prelink_size < ((num_modules + 1) * sizeof(kmod_info_t)))) { fprintf(stderr, "read prelinkstate failed\n"); err = kKXKextManagerErrorFileAccess; goto finish; } if (verbose_level > 0) { verbose_log("%d modules - code VM 0x%lx - 0x%x (0x%lx, %.2f Mb)", num_modules, prelinkseg->vmaddr, nextKernelVM, nextKernelVM - prelinkseg->vmaddr, ((float)(nextKernelVM - prelinkseg->vmaddr)) / 1024.0 / 1024.0 ); } // map files, get sizes files = (struct FileInfo *) calloc(num_modules, sizeof(struct FileInfo)); totalModuleBytes = 0; for (idx = 0; idx < num_modules; idx++) { files[idx].key = CFStringCreateWithCString(kCFAllocatorDefault, prelink_state->modules[1+idx].name, kCFStringEncodingMacRoman); files[idx].kext = KXKextManagerGetKextWithIdentifier(theKextManager, files[idx].key); if (!prelink_state->modules[1+idx].size) continue; if (kKXKextManagerErrorNone != (err = readFile(prelink_state->modules[1+idx].name, &files[idx].mapped, &files[idx].mappedSize))) goto finish; header = (struct module_header *) files[idx].mapped; files[idx].swapped = kld_macho_swap(&header->h); files[idx].code = (LC_SEGMENT == header->seg[0].cmd); if (files[idx].code) totalModuleBytes += header->seg[0].vmaddr + round_page(header->seg[0].vmsize) - prelink_state->modules[1+idx].address; } totalSymbolBytes = 0; totalSymbolDiscardedBytes = 0; totalSymbolSetBytes = 0; remainingModuleBytes = totalModuleBytes; // create prelinked kernel file outfd = open("mach_kernel.prelink", O_WRONLY|O_CREAT|O_TRUNC, 0666); if (-1 == outfd) { fprintf(stderr, "can't create %s: %s\n", "mach_kernel.prelink", strerror(errno)); err = kKXKextManagerErrorFileAccess; goto finish; } // start writing at the prelink segs file offset if (-1 == lseek(outfd, prelinkseg->fileoff, SEEK_SET)) { perror("couldn't write output"); err = kKXKextManagerErrorFileAccess; goto finish; } for (idx = 0, lastInfo = NULL; idx < num_modules; idx++) { kmod_info_t * info; unsigned long modcmd; struct symtab_command * symcmd; struct section * sect; vm_size_t headerOffset; if (!files[idx].code && prelink_state->modules[1+idx].size) { // for symbol sets the whole file ends up in the symbol sect files[idx].symtaboffset = 0; files[idx].symtabsize = prelink_state->modules[1+idx].size; files[idx].symbolsetoffset = totalSymbolBytes; totalSymbolBytes += files[idx].symtabsize; totalSymbolSetBytes += files[idx].symtabsize; continue; } header = (struct module_header *) files[idx].mapped; // patch kmod_info info = (kmod_info_t *) (prelink_state->modules[1+idx].id - header->seg[0].vmaddr + header->seg[0].fileoff + files[idx].mapped); info->next = lastInfo; lastInfo = info; bcopy(prelink_state->modules[1+idx].name, info->name, sizeof(info->name)); bcopy(prelink_state->modules[1+idx].version, info->version, sizeof(info->version)); info->address = prelink_state->modules[1+idx].address; info->size = prelink_state->modules[1+idx].size; info->id = prelink_state->modules[1+idx].id; info->hdr_size = header->seg[0].vmaddr - prelink_state->modules[1+idx].address; // patch offsets // how far back the header moves headerOffset = info->hdr_size - header->seg[0].fileoff; header->seg[0].fileoff += headerOffset; header->seg[0].filesize += headerOffset; // module code size tailoffset = round_page(header->seg[0].vmsize) + info->hdr_size - headerOffset; for (modcmd = 0, sect = (struct section *) &header->seg[1]; modcmd < header->seg[0].nsects; modcmd++, sect++) sect->offset += headerOffset; for (modcmd = 0, seg = &header->seg[0]; (modcmd < header->h.ncmds) && (LC_SYMTAB != seg->cmd); modcmd++, seg = (struct segment_command *)(((vm_offset_t)seg) + seg->cmdsize)) {} if (modcmd >= header->h.ncmds) { fprintf(stderr, "No LC_SYMTAB in %s\n", prelink_state->modules[1+idx].name); err = kKXKextManagerErrorLinkLoad; goto finish; } symcmd = (struct symtab_command *) seg; theKext = files[idx].kext; if (false && theKext && (kextBundle = KXKextGetBundle(theKext)) && CFBundleGetValueForInfoDictionaryKey(kextBundle, CFSTR("OSBundleCompatibleVersion"))) { // keeping symbols for this module struct nlist * sym; long align, lastUsedOffset = 0; const char * lastUsedString; unsigned int strIdx; files[idx].symtaboffset = symcmd->symoff; files[idx].symtabsize = symcmd->nsyms * sizeof(struct nlist); // .. but just the external strings sym = (struct nlist *) (symcmd->symoff + files[idx].mapped); for(strIdx = 0; strIdx < symcmd->nsyms; strIdx++, sym++) { if (!lastUsedOffset) lastUsedOffset = sym->n_un.n_strx; else if (!(sym->n_type & N_EXT)) sym->n_un.n_strx = 0; else if (sym->n_un.n_strx > lastUsedOffset) lastUsedOffset = sym->n_un.n_strx; } lastUsedString = (const char *) (symcmd->stroff + lastUsedOffset + files[idx].mapped); lastUsedOffset += (1 + strlen(lastUsedString)); align = lastUsedOffset % sizeof(long); if (align) { align = sizeof(long) - align; bzero((void *) (symcmd->stroff + lastUsedOffset + files[idx].mapped), align); lastUsedOffset += align; } files[idx].symtabsize += lastUsedOffset; files[idx].symtabdiscarded = symcmd->strsize - lastUsedOffset; symcmd->strsize = lastUsedOffset; // unswap symbols kld_macho_unswap(&header->h, files[idx].swapped, 1); // patch offset to symbols // how far ahead the symtab moves bytes = remainingModuleBytes + totalSymbolBytes; symcmd->symoff = bytes; symcmd->stroff += bytes - files[idx].symtaboffset; totalSymbolBytes += files[idx].symtabsize; totalSymbolDiscardedBytes += files[idx].symtabdiscarded; } else { // ditching symbols for this module files[idx].symtaboffset = 0; files[idx].symtabsize = 0; symcmd->nsyms = 0; symcmd->symoff = 0; symcmd->stroff = 0; } remainingModuleBytes -= prelink_state->modules[1+idx].size; // unswap rest of module if (files[idx].swapped) { info->next = (void *) NXSwapLong((long) info->next); info->address = NXSwapLong(info->address); info->size = NXSwapLong(info->size); info->hdr_size = NXSwapLong(info->hdr_size); info->id = NXSwapLong(info->id); } kld_macho_unswap(&header->h, files[idx].swapped, -1); files[idx].swapped = false; header = 0; info = 0; // copy header to start of VM allocation if (kKXKextManagerErrorNone != (err = writeFile(outfd, (const void *) files[idx].mapped, headerOffset))) goto finish; // write the module if (kKXKextManagerErrorNone != (err = writeFile(outfd, (const void *) files[idx].mapped, tailoffset ))) goto finish; } // write the symtabs, get info, unmap for (idx = 0; idx < num_modules; idx++) { bytes = files[idx].symtabsize; if (bytes && prelink_state->modules[1+idx].size) { if (files[idx].mappedSize < (files[idx].symtaboffset + bytes)) { fprintf(stderr, "%s is truncated\n", prelink_state->modules[1+idx].name); result = kKXKextManagerErrorFileAccess; goto finish; } else if (files[idx].mappedSize > (files[idx].symtaboffset + bytes + files[idx].symtabdiscarded)) fprintf(stderr, "%s has extra data\n", prelink_state->modules[1+idx].name); // write symtab if (kKXKextManagerErrorNone != (err = writeFile(outfd, (const void *) files[idx].mapped + files[idx].symtaboffset, bytes))) goto finish; } // unmap file if (files[idx].mappedSize) { vm_deallocate(mach_task_self(), files[idx].mapped, files[idx].mappedSize); files[idx].mapped = 0; files[idx].mappedSize = 0; } // make info dict theKext = files[idx].kext; infoDict = NULL; includeInfo = (theKext && (kextBundle = KXKextGetBundle(theKext))); if (includeInfo && !all_plists) { CFStringRef str; // check OSBundleRequired to see if safe for boot time matching str = CFBundleGetValueForInfoDictionaryKey(kextBundle, CFSTR("OSBundleRequired")); includeInfo = (str && (kCFCompareEqualTo != CFStringCompare(str, CFSTR("Safe Boot"), 0))); } if (includeInfo) infoDict = copyInfoDict(kextBundle); if (!infoDict) { if (debug_mode > 0) { verbose_log("skip info for %s", prelink_state->modules[1+idx].name); } infoDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(infoDict, CFSTR("CFBundleIdentifier"), files[idx].key); } CFRelease(files[idx].key); files[idx].key = 0; if (prelink_state->modules[1+idx].address) { CFMutableDataRef data; enum { kPrelinkReservedCount = 4 }; UInt32 prelinkInfo[kPrelinkReservedCount]; prelinkInfo[0] = NXSwapHostIntToBig(prelink_state->modules[1+idx].id); prelinkInfo[1] = NXSwapHostIntToBig(0); prelinkInfo[2] = NXSwapHostIntToBig(sizeof(prelinkInfo)); prelinkInfo[3] = NXSwapHostIntToBig( prelink_state->modules[1+idx].reference_count * sizeof(UInt32) + sizeof(prelinkInfo)); data = CFDataCreateMutable(kCFAllocatorDefault, 0); CFDataAppendBytes( data, (const UInt8 *) prelinkInfo, sizeof(prelinkInfo) ); if (prelink_state->modules[1+idx].reference_count) { CFIndex start = (CFIndex) prelink_state->modules[1+idx].reference_list; CFDataAppendBytes( data, (const UInt8 *) &prelink_dependencies[start], prelink_state->modules[1+idx].reference_count * sizeof(CFIndex) ); } CFDictionarySetValue(infoDict, CFSTR("OSBundlePrelink"), data); CFRelease(data); } else if (files[idx].symtabsize) { CFNumberRef num; num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, (const void *) &files[idx].symbolsetoffset); CFDictionarySetValue(infoDict, CFSTR("OSBundlePrelinkSymbols"), num); CFRelease(num); } CFArrayAppendValue(moduleList, infoDict); CFRelease(infoDict); } bytes = round_page(totalSymbolBytes) - totalSymbolBytes; totalSymbolBytes += bytes; if (-1 == lseek(outfd, bytes, SEEK_CUR)) { perror("couldn't write output"); err = kKXKextManagerErrorFileAccess; goto finish; } // deferred load __info if (!all_plists) for (i = 0; i < kexts_count; i++) { theKext = (KXKextRef) kexts[i]; for (idx = 0; (idx < num_modules) && (theKext != files[idx].kext); idx++) {} if (idx < num_modules) continue; includeInfo = (theKext && (kextBundle = KXKextGetBundle(theKext))); if (includeInfo) { CFStringRef str; // check OSBundleRequired to see if safe for boot time matching str = CFBundleGetValueForInfoDictionaryKey(kextBundle, CFSTR("OSBundleRequired")); includeInfo = (str && (kCFCompareEqualTo != CFStringCompare(str, CFSTR("Safe Boot"), 0))); if (includeInfo) { infoDict = copyInfoDict(kextBundle); if (infoDict) { CFDictionarySetValue(infoDict, CFSTR("OSBundleDefer"), kCFBooleanTrue); CFArrayAppendValue(moduleList, infoDict); CFRelease(infoDict); } } } } // write __info { CFDataRef data; data = IOCFSerialize(moduleList, kNilOptions); if (!data) { fprintf(stderr, "couldn't serialize property lists\n"); err = kKXKextManagerErrorSerialization; goto finish; } totalInfoBytes = round_page(CFDataGetLength(data)); if (kKXKextManagerErrorNone != (err = writeFile(outfd, CFDataGetBytePtr(data), CFDataGetLength(data)))) goto finish; if (-1 == lseek(outfd, totalInfoBytes - CFDataGetLength(data), SEEK_CUR)) { perror("couldn't write output"); err = kKXKextManagerErrorFileAccess; goto finish; } CFRelease(data); } totalBytes = totalModuleBytes + totalSymbolBytes + totalInfoBytes; if (verbose_level > 0) { verbose_log("added 0x%x bytes %.2f Mb (code 0x%x + symbol 0x%x + sets 0x%x - strings 0x%x + info 0x%x)", totalBytes, ((float) totalBytes) / 1024.0 / 1024.0, totalModuleBytes, totalSymbolBytes, totalSymbolSetBytes, totalSymbolDiscardedBytes, totalInfoBytes); } fileoffset = totalBytes - prelinkseg->filesize; vmoffset = totalBytes - round_page(prelinkseg->filesize); // unswap kernel symbols kld_macho_unswap((struct mach_header *)kernel_map, kernel_swapped, 1); // write tail of base kernel tailoffset = prelinkseg->fileoff + prelinkseg->filesize; if (kKXKextManagerErrorNone != (err = writeFile(outfd, (const void *) (kernel_map + tailoffset), kernel_size - tailoffset))) goto finish; // patch prelink sects sizes and offsets prelinkseg->vmsize = totalBytes; prelinkseg->filesize = totalBytes; prelinksects[0].size = totalModuleBytes; prelinksects[1].addr = prelinksects[0].addr + totalModuleBytes; prelinksects[1].size = totalSymbolBytes; prelinksects[1].offset = prelinksects[0].offset + totalModuleBytes; prelinksects[2].addr = prelinksects[1].addr + totalSymbolBytes; prelinksects[2].size = totalInfoBytes; prelinksects[2].offset = prelinksects[1].offset + totalSymbolBytes; // patch following segs address & offsets seg = prelinkseg; for (; cmd < ncmds; cmd++) { seg = (struct segment_command *)(((vm_offset_t)seg) + seg->cmdsize); if (LC_SYMTAB == seg->cmd) { ((struct symtab_command *)seg)->symoff += fileoffset; ((struct symtab_command *)seg)->stroff += fileoffset; } else if (LC_SEGMENT == seg->cmd) { seg->fileoff += fileoffset; seg->vmaddr += vmoffset; } } bytes = prelinkseg->fileoff; // unswap kernel headers kld_macho_unswap((struct mach_header *)kernel_map, kernel_swapped, -1); kernel_swapped = false; prelinkseg = 0; // write head of base kernel, & free it if (-1 == lseek(outfd, 0, SEEK_SET)) { perror("couldn't write output"); err = kKXKextManagerErrorFileAccess; goto finish; } if (kKXKextManagerErrorNone != (err = writeFile(outfd, (const void *) kernel_map, bytes))) goto finish; close(outfd); outfd = -1; vm_deallocate( mach_task_self(), kernel_file, kernel_file_size ); kernel_file = 0; kernel_map = 0; } // compresss { char * buf; char * bufend; vm_size_t bufsize; struct { uint32_t signature; uint32_t compress_type; uint32_t adler32; vm_size_t uncompressed_size; vm_size_t compressed_size; uint32_t reserved[11]; char platform_name[64]; char root_path[256]; char data[0]; } kernel_header = { 0 }; if (kKXKextManagerErrorNone != (err = readFile("mach_kernel.prelink", &kernel_file, &kernel_file_size))) goto finish; bufsize = kernel_file_size; buf = malloc(bufsize); kernel_header.signature = NXSwapHostIntToBig('comp'); kernel_header.compress_type = NXSwapHostIntToBig('lzss'); kernel_header.adler32 = NXSwapHostIntToBig(local_adler32( (u_int8_t *) kernel_file, kernel_file_size)); kernel_header.uncompressed_size = NXSwapHostIntToBig(kernel_file_size); strcpy(kernel_header.platform_name, platform_name); strcpy(kernel_header.root_path, root_path); if (verbose_level > 0) verbose_log("adler32 0x%08x, compressing...", NXSwapBigIntToHost(kernel_header.adler32)); bufend = compress_lzss(buf, bufsize, (u_int8_t *) kernel_file, kernel_file_size); totalBytes = bufend - buf; kernel_header.compressed_size = NXSwapHostIntToBig(totalBytes); if (verbose_level > 0) verbose_log("final size 0x%x bytes %.2f Mb", totalBytes, ((float) totalBytes) / 1024.0 / 1024.0); vm_deallocate( mach_task_self(), kernel_file, kernel_file_size ); outfd = open(temp_file, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (-1 == outfd) { fprintf(stderr, "can't create %s - %s\n", temp_file, strerror(errno)); err = kKXKextManagerErrorFileAccess; goto finish; } // write header if (kKXKextManagerErrorNone != (err = writeFile(outfd, &kernel_header, sizeof(kernel_header)))) goto finish; // write compressed data if (kKXKextManagerErrorNone != (err = writeFile(outfd, buf, bufend - buf))) goto finish; close(outfd); outfd = -1; } // move it to the final destination if (-1 == rename(temp_file, kernelCacheFilename)) { fprintf(stderr, "can't create file %s: %s\n", kernelCacheFilename, strerror(errno)); err = kKXKextManagerErrorFileAccess; goto finish; } if (verbose_level > 0) verbose_log("created cache: %s", kernelCacheFilename); result = kKXKextManagerErrorNone; finish: if (-1 != outfd) close(outfd); if (debug_mode) symbol_dir[0] = 0; if (symbol_dir[0]) { FTS * fts; FTSENT * fts_entry; char * paths[2]; paths[0] = symbol_dir; paths[1] = 0; fts = fts_open(paths, FTS_NOCHDIR, NULL); if (fts) { while ((fts_entry = fts_read(fts))) { if (fts_entry->fts_errno) continue; if (FTS_F != fts_entry->fts_info) continue; if (-1 == unlink(fts_entry->fts_path)) fprintf(stderr, "can't remove file %s: %s\n", fts_entry->fts_path, strerror(errno)); } fts_close(fts); } } if (-1 != curwd) fchdir(curwd); if (symbol_dir[0] && (-1 == rmdir(symbol_dir))) perror("rmdir"); if (kexts) free(kexts); if (files) free(files); return result; }
static int listen_for_IP() { struct sockaddr_nl addr; int sock, len; const int RECV_SIZE = 512; char recv_buffer[RECV_SIZE]; if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { _perror("couldn't open NETLINK_ROUTE socket"); _assert(false); return 1; } memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_groups = RTMGRP_IPV6_IFADDR; if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { _perror("couldn't bind"); assert(false); return 1; } send_ip_list_request(sock); loop: while ((len = recv(sock, recv_buffer, RECV_SIZE, 0)) > 0) { struct nlmsghdr* nlh = (struct nlmsghdr*) recv_buffer; while (NLMSG_OK(nlh, len) && (nlh->nlmsg_type != NLMSG_DONE)) { if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_GETADDR || nlh->nlmsg_type == RTM_DELADDR) { struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh); if(verbose_mode) { log_time(); log("Message: [%d] flags: ", nlh->nlmsg_type); fprint_flags(global_output, ifa->ifa_flags); log(" scope: %d\n", ifa->ifa_scope); } if (ifa->ifa_family == AF_INET6) { void *address = NULL; //The IP Address: struct ifa_cacheinfo *ci = NULL; //Cache info for address: struct rtattr *rth = IFA_RTA(ifa); int rtl = IFA_PAYLOAD(nlh); while (rtl && RTA_OK(rth, rtl)) { if (rth->rta_type == IFA_ADDRESS) { address = RTA_DATA(rth); if(verbose_mode) { log("[IFA_ADDRESS]"); log_ipv6(address); log("\n"); } } else if (rth->rta_type == IFA_CACHEINFO) { ci = (struct ifa_cacheinfo *) RTA_DATA(rth); if(verbose_mode) { log("[IFA_CACHEINFO] valid: %d prefered: %d\n", ci->ifa_valid, ci->ifa_prefered); } } else { verbose_log("[?%d?]\n", rth->rta_type); } rth = RTA_NEXT(rth, rtl); } assert(address != NULL); assert(ci != NULL); filter_ip(address, ifa->ifa_flags, ifa->ifa_scope, ci->ifa_prefered); } } else if (nlh->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*) NLMSG_DATA(nlh); if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { log("ERROR truncated\n"); } else { errno = -err->error; _perror("RTNETLINK answers"); } return -1; } nlh = NLMSG_NEXT(nlh, len); } fflush(global_output); } if (errno == EINTR || errno == EAGAIN) goto loop; //Would a do..while be cleaner? assert(len != 0); assert(len > 0); return 0; }