/** * Beware! The getsect* functions do NOT play well with ASLR, so we cannot just * copy the data out of the memory address at sect->addr. We could link this * with -Wl,-no_pie, but it is easier to just open the binary and read it from * disk. */ CAMLprim value get_embedded_flowlib_data(value filename) { CAMLparam1(filename); CAMLlocal1(result); const struct section_64 *sect = getsectbyname("__text", "flowlib"); if (sect == NULL) { goto fail_early; } int fd = open(String_val(filename), O_RDONLY); if (fd < 0) { goto fail_early; } lseek(fd, sect->offset, SEEK_SET); result = caml_alloc_string(sect->size); if (read(fd, String_val(result), sect->size) != sect->size) { goto fail_after_open; } close(fd); CAMLreturn(SOME(result)); fail_after_open: close(fd); fail_early: CAMLreturn(NONE); }
void KLDBootstrap::readStartupExtensions(void) { kernel_section_t * prelinkInfoSect = NULL; // do not free OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, "Reading startup extensions."); /* If the prelink info segment has a nonzero size, we are prelinked * and won't have any individual kexts or mkexts to read. * Otherwise, we need to read kexts or the mkext from what the booter * has handed us. */ prelinkInfoSect = getsectbyname(kPrelinkInfoSegment, kPrelinkInfoSection); if (prelinkInfoSect->size) { readPrelinkedExtensions(prelinkInfoSect); } else { readBooterExtensions(); } loadKernelComponentKexts(); loadKernelExternalComponents(); readBuiltinPersonalities(); OSKext::sendAllKextPersonalitiesToCatalog(); return; }
TFilePtr CNativePosix::GetInternalFile(const std::string& aFilename) { LOG_METHOD(); if (aFilename != internal_cabinet_name) { LOG_ERROR("Unknown resource file %s", aFilename.c_str()); return TFilePtr(); } TFileData fileData; LOG_DEBUG("Getting section binary"); const struct segment_command_64* segment = getsegbyname("binary"); if (segment == nullptr) { LOG_DEBUG("Section binary not found."); } LOG_DEBUG("Loading binary data section %s", internal_cabinet_section_name); const struct section_64* sect = getsectbyname("binary", internal_cabinet_section_name); if (sect == nullptr) { LOG_ERROR("Internal data section not found: %s", internal_cabinet_section_name); return GetResourceFile(aFilename); } LOG_DEBUG("Found data section of size %" PRIu64, sect->size); const char* end = (char*)sect->addr + sect->size; for (const char* data = (char*)sect->addr; data != end; data++) { fileData.push_back(*data); } return std::make_shared<CMemoryFile>(std::move(fileData)); }
/* * This returns what was the value of the UNIX link editor defined symbol * _etext (the first address after the text section). Note this my or may not * be the only section in the __TEXT segment. */ unsigned long get_etext(void) { struct section *sp; sp = getsectbyname(SEG_TEXT, SECT_TEXT); if(sp) return(sp->addr + sp->size); else return(0); }
/* * This returns what was the value of the UNIX link editor defined symbol * _edata (the first address after the data section). Note this my or may not * be the last non-zero fill section in the __DATA segment. */ unsigned long get_edata(void) { struct section *sp; sp = getsectbyname(SEG_DATA, SECT_DATA); if(sp) return(sp->addr + sp->size); else return(0); }
bool get_embedded_data(const char* section, embedded_data* desc, const std::string& filename /*= "" */) { auto const fname = filename.empty() ? current_executable_path() : filename; #if defined(__CYGWIN__) || defined(__MINGW__) || defined(_MSC_VER) HMODULE moduleHandle = GetModuleHandleA(fname.data()); HGLOBAL loadedResource; HRSRC resourceInfo; DWORD resourceSize; resourceInfo = FindResource(moduleHandle, section, RT_RCDATA); if (!resourceInfo) { return false; } loadedResource = LoadResource(moduleHandle, resourceInfo); if (!loadedResource) { return false; } resourceSize = SizeofResource(moduleHandle, resourceInfo); desc->m_filename = fname; desc->m_handle = loadedResource; desc->m_len = resourceSize; return true; #elif !defined(__APPLE__) // LINUX/ELF folly::symbolizer::ElfFile file; if (file.openNoThrow(fname.c_str()) != 0) return false; auto const shdr = file.getSectionByName(section); if (shdr == nullptr) return false; desc->m_filename = fname; desc->m_start = shdr->sh_offset; desc->m_len = shdr->sh_size; return true; #else // __APPLE__ const struct section_64 *sect = getsectbyname("__text", section); if (sect) { desc->m_filename = fname; desc->m_start = sect->offset; desc->m_len = sect->size; return !desc->m_filename.empty(); } #endif // __APPLE__ return false; }
/* * This returns what was the value of the UNIX link editor defined symbol * _edata (the first address after the data section). Note this my or may not * be the last non-zero fill section in the __DATA segment. */ unsigned long get_edata(void) { #ifndef __LP64__ const struct section *sp; #else /* defined(__LP64__) */ const struct section_64 *sp; #endif /* defined(__LP64__) */ sp = getsectbyname(SEG_DATA, SECT_DATA); if(sp) return(sp->addr + sp->size); else return(0); }
static int get_data_region( vm_address_t *address, vm_size_t *size ) { region_t region; kern_return_t ret; struct section *sect; sect = (struct section *) getsectbyname(SEG_DATA, SECT_DATA); region.address = 0; *address = 0; for (;;) { ret = vm_region(task_self(), ®ion.address, ®ion.size, ®ion.protection, ®ion.max_protection, ®ion.inheritance, ®ion.shared, ®ion.object_name, ®ion.offset); if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) { break; } if (*address != 0) { if (region.address > *address + *size) { if (!filldatagap(*address, size, region.address)) { return (0); } } *size += region.size; } else { if (region.address == sect->addr) { *address = region.address; *size = region.size; } } region.address += region.size; } return (1); }
/* * This routine returns the a pointer to the data for the named section in the * named segment if it exist in the mach executable it is linked into. Also * it returns the size of the section data indirectly through the pointer size. * Otherwise it returns zero for the pointer and the size. */ char * getsectdata( const char *segname, const char *sectname, unsigned long *size) { #ifndef __LP64__ const struct section *sp; #else /* defined(__LP64__) */ const struct section_64 *sp; #endif /* defined(__LP64__) */ sp = getsectbyname(segname, sectname); if(sp == NULL) { *size = 0; return(NULL); } *size = sp->size; return((char *)(sp->addr)); }
void KLDBootstrap::readBuiltinPersonalities(void) { OSObject * parsedXML = NULL; // must release OSArray * builtinExtensions = NULL; // do not release OSArray * allPersonalities = NULL; // must release OSString * errorString = NULL; // must release kernel_section_t * infosect = NULL; // do not free OSCollectionIterator * personalitiesIterator = NULL; // must release unsigned int count, i; OSKextLog(/* kext */ NULL, kOSKextLogStepLevel | kOSKextLogLoadFlag, "Reading built-in kernel personalities for I/O Kit drivers."); /* Look in the __BUILTIN __info segment for an array of Info.plist * entries. For each one, extract the personalities dictionary, add * it to our array, then push them all (without matching) to * the IOCatalogue. This can be used to augment the personalities * in gIOKernelConfigTables, especially when linking entire kexts into * the mach_kernel image. */ infosect = getsectbyname("__BUILTIN", "__info"); if (!infosect) { // this isn't fatal goto finish; } parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr, &errorString); if (parsedXML) { builtinExtensions = OSDynamicCast(OSArray, parsedXML); } if (!builtinExtensions) { const char * errorCString = "(unknown error)"; if (errorString && errorString->getCStringNoCopy()) { errorCString = errorString->getCStringNoCopy(); } else if (parsedXML) { errorCString = "not an array"; } OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogLoadFlag, "Error unserializing built-in personalities: %s.", errorCString); goto finish; } // estimate 3 personalities per Info.plist/kext count = builtinExtensions->getCount(); allPersonalities = OSArray::withCapacity(count * 3); for (i = 0; i < count; i++) { OSDictionary * infoDict = NULL; // do not release OSString * moduleName = NULL; // do not release OSDictionary * personalities; // do not release OSString * personalityName; // do not release OSSafeReleaseNULL(personalitiesIterator); infoDict = OSDynamicCast(OSDictionary, builtinExtensions->getObject(i)); if (!infoDict) { continue; } moduleName = OSDynamicCast(OSString, infoDict->getObject(kCFBundleIdentifierKey)); if (!moduleName) { continue; } OSKextLog(/* kext */ NULL, kOSKextLogStepLevel | kOSKextLogLoadFlag, "Adding personalities for built-in driver %s:", moduleName->getCStringNoCopy()); personalities = OSDynamicCast(OSDictionary, infoDict->getObject("IOKitPersonalities")); if (!personalities) { continue; } personalitiesIterator = OSCollectionIterator::withCollection(personalities); if (!personalitiesIterator) { continue; // xxx - well really, what can we do? should we panic? } while ((personalityName = OSDynamicCast(OSString, personalitiesIterator->getNextObject()))) { OSDictionary * personality = OSDynamicCast(OSDictionary, personalities->getObject(personalityName)); OSKextLog(/* kext */ NULL, kOSKextLogDetailLevel | kOSKextLogLoadFlag, "Adding built-in driver personality %s.", personalityName->getCStringNoCopy()); if (personality && !personality->getObject(kCFBundleIdentifierKey)) { personality->setObject(kCFBundleIdentifierKey, moduleName); } allPersonalities->setObject(personality); } } gIOCatalogue->addDrivers(allPersonalities, false); finish: OSSafeReleaseNULL(parsedXML); OSSafeReleaseNULL(allPersonalities); OSSafeReleaseNULL(errorString); OSSafeReleaseNULL(personalitiesIterator); return; }
void KLDBootstrap::readPrelinkedExtensions( kernel_section_t * prelinkInfoSect) { OSArray * infoDictArray = NULL; // do not release OSArray * personalitiesArray = NULL; // do not release OSObject * parsedXML = NULL; // must release OSDictionary * prelinkInfoDict = NULL; // do not release OSString * errorString = NULL; // must release OSKext * theKernel = NULL; // must release #if CONFIG_KXLD kernel_section_t * kernelLinkStateSection = NULL; // see code #endif kernel_segment_command_t * prelinkLinkStateSegment = NULL; // see code kernel_segment_command_t * prelinkTextSegment = NULL; // see code kernel_segment_command_t * prelinkInfoSegment = NULL; // see code /* We make some copies of data, but if anything fails we're basically * going to fail the boot, so these won't be cleaned up on error. */ void * prelinkData = NULL; // see code void * prelinkCopy = NULL; // see code vm_size_t prelinkLength = 0; #if !__LP64__ && !defined(__arm__) vm_map_offset_t prelinkDataMapOffset = 0; #endif kern_return_t mem_result = KERN_SUCCESS; OSDictionary * infoDict = NULL; // do not release IORegistryEntry * registryRoot = NULL; // do not release OSNumber * prelinkCountObj = NULL; // must release u_int i = 0; OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, "Starting from prelinked kernel."); /***** * Wrap the kernel link state in-place in an OSData. * This is unnecessary (and the link state may not be present) if the kernel * does not have kxld support because this information is only used for * runtime linking. */ #if CONFIG_KXLD kernelLinkStateSection = getsectbyname(kPrelinkLinkStateSegment, kPrelinkKernelLinkStateSection); if (!kernelLinkStateSection) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, "Can't find prelinked kernel link state."); goto finish; } theKernel = OSKext::lookupKextWithIdentifier(kOSKextKernelIdentifier); if (!theKernel) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, "Can't find kernel kext object in prelinked kernel."); goto finish; } prelinkData = (void *) kernelLinkStateSection->addr; prelinkLength = kernelLinkStateSection->size; mem_result = kmem_alloc_pageable(kernel_map, (vm_offset_t *) &prelinkCopy, prelinkLength); if (mem_result != KERN_SUCCESS) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, "Can't copy prelinked kernel link state."); goto finish; } memcpy(prelinkCopy, prelinkData, prelinkLength); theKernel->linkState = OSData::withBytesNoCopy(prelinkCopy, prelinkLength); if (!theKernel->linkState) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, "Can't create prelinked kernel link state wrapper."); goto finish; } theKernel->linkState->setDeallocFunction(osdata_kmem_free); #endif prelinkTextSegment = getsegbyname(kPrelinkTextSegment); if (!prelinkTextSegment) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, "Can't find prelinked kexts' text segment."); goto finish; } prelinkData = (void *) prelinkTextSegment->vmaddr; prelinkLength = prelinkTextSegment->vmsize; #if !__LP64__ /* To enable paging and write/execute protections on the kext * executables, we need to copy them out of the booter-created * memory, reallocate that space with VM, then prelinkCopy them back in. * This isn't necessary on LP64 because kexts have their own VM * region on that architecture model. */ mem_result = kmem_alloc(kernel_map, (vm_offset_t *)&prelinkCopy, prelinkLength); if (mem_result != KERN_SUCCESS) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, "Can't copy prelinked kexts' text for VM reassign."); goto finish; } /* Copy it out. */ memcpy(prelinkCopy, prelinkData, prelinkLength); /* Dump the booter memory. */ ml_static_mfree((vm_offset_t)prelinkData, prelinkLength); /* Set up the VM region. */ prelinkDataMapOffset = (vm_map_offset_t)(uintptr_t)prelinkData; mem_result = vm_map_enter_mem_object( kernel_map, &prelinkDataMapOffset, prelinkLength, /* mask */ 0, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, (ipc_port_t)NULL, (vm_object_offset_t) 0, /* copy */ FALSE, /* cur_protection */ VM_PROT_ALL, /* max_protection */ VM_PROT_ALL, /* inheritance */ VM_INHERIT_DEFAULT); if ((mem_result != KERN_SUCCESS) || (prelinkTextSegment->vmaddr != prelinkDataMapOffset)) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, "Can't create kexts' text VM entry at 0x%llx, length 0x%x (error 0x%x).", (unsigned long long) prelinkDataMapOffset, prelinkLength, mem_result); goto finish; } prelinkData = (void *)(uintptr_t)prelinkDataMapOffset; /* And copy it back. */ memcpy(prelinkData, prelinkCopy, prelinkLength); kmem_free(kernel_map, (vm_offset_t)prelinkCopy, prelinkLength); #endif /* !__LP64__ */ /* Unserialize the info dictionary from the prelink info section. */ parsedXML = OSUnserializeXML((const char *)prelinkInfoSect->addr, &errorString); if (parsedXML) { prelinkInfoDict = OSDynamicCast(OSDictionary, parsedXML); } if (!prelinkInfoDict) { const char * errorCString = "(unknown error)"; if (errorString && errorString->getCStringNoCopy()) { errorCString = errorString->getCStringNoCopy(); } else if (parsedXML) { errorCString = "not a dictionary"; } OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, "Error unserializing prelink plist: %s.", errorCString); goto finish; } infoDictArray = OSDynamicCast(OSArray, prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey)); if (!infoDictArray) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, "The prelinked kernel has no kext info dictionaries"); goto finish; } /* Create OSKext objects for each info dictionary. */ for (i = 0; i < infoDictArray->getCount(); ++i) { infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i)); if (!infoDict) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, "Can't find info dictionary for prelinked kext #%d.", i); continue; } /* Create the kext for the entry, then release it, because the * kext system keeps them around until explicitly removed. * Any creation/registration failures are already logged for us. */ OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict); OSSafeReleaseNULL(newKext); } /* Get all of the personalities for kexts that were not prelinked and * add them to the catalogue. */ personalitiesArray = OSDynamicCast(OSArray, prelinkInfoDict->getObject(kPrelinkPersonalitiesKey)); if (!personalitiesArray) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag, "The prelinked kernel has no personalities array"); goto finish; } if (personalitiesArray->getCount()) { OSKext::setPrelinkedPersonalities(personalitiesArray); } /* Store the number of prelinked kexts in the registry so we can tell * when the system has been started from a prelinked kernel. */ registryRoot = IORegistryEntry::getRegistryRoot(); assert(registryRoot); prelinkCountObj = OSNumber::withNumber( (unsigned long long)infoDictArray->getCount(), 8 * sizeof(uint32_t)); assert(prelinkCountObj); if (prelinkCountObj) { registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj); } OSSafeReleaseNULL(prelinkCountObj); prelinkCountObj = OSNumber::withNumber( (unsigned long long)personalitiesArray->getCount(), 8 * sizeof(uint32_t)); assert(prelinkCountObj); if (prelinkCountObj) { registryRoot->setProperty(kOSPrelinkPersonalityCountKey, prelinkCountObj); } OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag | kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, "%u prelinked kexts, and %u additional personalities.", infoDictArray->getCount(), personalitiesArray->getCount()); #if __LP64__ /* On LP64 systems, kexts are copied to their own special VM region * during OSKext init time, so we can free the whole segment now. */ ml_static_mfree((vm_offset_t) prelinkData, prelinkLength); #endif /* __LP64__ */ /* Free the link state segment, kexts have copied out what they need. */ prelinkLinkStateSegment = getsegbyname(kPrelinkLinkStateSegment); if (prelinkLinkStateSegment) { ml_static_mfree((vm_offset_t)prelinkLinkStateSegment->vmaddr, (vm_size_t)prelinkLinkStateSegment->vmsize); } /* Free the prelink info segment, we're done with it. */ prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment); if (prelinkInfoSegment) { ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr, (vm_size_t)prelinkInfoSegment->vmsize); } finish: OSSafeRelease(errorString); OSSafeRelease(parsedXML); OSSafeRelease(theKernel); OSSafeRelease(prelinkCountObj); return; }