Ejemplo n.º 1
0
/**
 * 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);
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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));
}
Ejemplo n.º 4
0
/*
 * 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);
}
Ejemplo n.º 5
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);
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
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)
{
#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);
}
Ejemplo n.º 8
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(), 
				&region.address, 
				&region.size, 
				&region.protection, 
				&region.max_protection, 
				&region.inheritance,
				&region.shared, 
				&region.object_name, 
				&region.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);
}
Ejemplo n.º 9
0
/*
 * 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));
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}