Exemplo n.º 1
0
OSReturn OSKextRetainKextWithLoadTag(uint32_t loadTag)
{
    OSReturn   result = kOSKextReturnNotFound;
    OSKext   * theKext = NULL;  // do not release; as this function is a retain

    if (loadTag == kOSKextInvalidLoadTag) {
        result = kOSKextReturnInvalidArgument;
        goto finish;
    }
    theKext = OSKext::lookupKextWithLoadTag(loadTag);
    if (theKext) {
        result = kOSReturnSuccess;

        OSKextLog(theKext,
            kOSKextLogDebugLevel |
            kOSKextLogKextBookkeepingFlag,
            "Kext %s (load tag %d) has been retained.",
            theKext->getIdentifierCString(),
            loadTag);

       /* Call this after so a log message about autounload comes second.
        */
        theKext->setAutounloadEnabled(true);
    } else {
        OSKextLog(theKext,
            kOSKextLogErrorLevel |
            kOSKextLogKextBookkeepingFlag,
            "Can't retain kext with load tag %d - no such kext is loaded.",
           loadTag);
    }
finish:
    return result;
}
Exemplo n.º 2
0
OSReturn OSKextReleaseKextWithLoadTag(uint32_t loadTag)
{
    OSReturn result  = kOSKextReturnNotFound;
    OSKext * theKext = NULL;  // must release twice!
    
    if (loadTag == kOSKextInvalidLoadTag) {
        result = kOSKextReturnInvalidArgument;
        goto finish;
    }
    theKext = OSKext::lookupKextWithLoadTag(loadTag);
    if (theKext) {
        result = kOSReturnSuccess;
        OSKext::considerUnloads();  // schedule autounload pass
        theKext->release();  // do the release the caller wants
        theKext->release();  // now do the release on the lookup
        OSKextLog(theKext,
            kOSKextLogDebugLevel |
            kOSKextLogKextBookkeepingFlag,
            "Kext %s (load tag %d) has been released.",
            theKext->getIdentifierCString(),
            loadTag);
    } else {
        OSKextLog(theKext,
            kOSKextLogErrorLevel |
            kOSKextLogKextBookkeepingFlag,
            "Can't release kext with load tag %d - no such kext is loaded.",
           loadTag);
    }
    
    // xxx - should I check that the refcount of the OSKext is above the lower bound?
    // xxx - do we want a OSKextGetRetainCountOfKextWithLoadTag()?
finish:
    return result;
}
Exemplo n.º 3
0
kern_return_t OSKextPingKextd(void)
{
    kern_return_t result     = KERN_FAILURE;
    mach_port_t   kextd_port = IPC_PORT_NULL;

    result = host_get_kextd_port(host_priv_self(), &kextd_port);
    if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
	OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogIPCFlag,
            "Can't get kextd port.");
        goto finish;
    }

    result = kextd_ping(kextd_port);
    if (result != KERN_SUCCESS) {
	OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogIPCFlag,
            "kextd ping failed (0x%x).", (int)result);
        goto finish;
    }

finish:
    if (IPC_PORT_VALID(kextd_port)) {
        ipc_port_release_send(kextd_port);
    }

    return result;
}
Exemplo n.º 4
0
ExitStatus checkKextForProblems(
        KcgenArgs         * toolArgs,
        OSKextRef           theKext,
        const NXArchInfo  * arch)
{
    ExitStatus          result        = EX_SOFTWARE;
    char                kextPath[PATH_MAX];

    if (!CFURLGetFileSystemRepresentation(OSKextGetURL(theKext),
                              /* resolveToBase */ false, (UInt8 *)kextPath, sizeof(kextPath))) 
    {
        strlcpy(kextPath, "(unknown)", sizeof(kextPath));
    }
    
    /* Skip kexts we have no interest in for the current arch.
     */
    if (!OSKextSupportsArchitecture(theKext, arch)) {
        OSKextLog(/* kext */ NULL,
                  kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
                  "%s doesn't support architecture '%s'; ommiting.", kextPath,
                  arch->name);
        goto finish;
    }
    
    if (!OSKextIsValid(theKext)) {
        OSKextLog(/* kext */ NULL,
                  kOSKextLogErrorLevel | kOSKextLogArchiveFlag |
                  kOSKextLogValidationFlag | kOSKextLogGeneralFlag, 
                  "%s is not valid; omitting.", kextPath);
        if (toolArgs->printTestResults) {
            OSKextLogDiagnostics(theKext, kOSKextDiagnosticsFlagAll);
        }
        goto finish;
    }
    
    if (!OSKextResolveDependencies(theKext)) {
        OSKextLog(/* kext */ NULL,
                  kOSKextLogWarningLevel | kOSKextLogArchiveFlag |
                  kOSKextLogDependenciesFlag | kOSKextLogGeneralFlag, 
                  "%s is missing dependencies (including anyway; "
                  "dependencies may be available from elsewhere)", kextPath);
        if (toolArgs->printTestResults) {
            OSKextLogDiagnostics(theKext, kOSKextDiagnosticsFlagAll);
        }
    }

    result = EX_OK;
    
finish:
    return result;

}
Exemplo n.º 5
0
/******************************************************************************
 * _kextmanager_lock_volume tries to lock volumes for clients (kextutil)
 *****************************************************************************/
kern_return_t _kextmanager_lock_kextload(
    mach_port_t server,
    mach_port_t client,
    int * lockstatus)
{
    kern_return_t mig_result = KERN_FAILURE;
    int result;

    if (!lockstatus) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
            "kextmanager_lock_kextload requires non-NULL lockstatus.");
        mig_result = KERN_SUCCESS;
        result = EINVAL;
        goto finish;
    }

    if (gClientUID != 0) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel,
            "Non-root process doesn't need to lock as it will fail to load.");
        mig_result = KERN_SUCCESS;
        result = EPERM;
        goto finish;
    }

    if (_gKextutilLock) {
        mig_result = KERN_SUCCESS;
        result = EBUSY;
        goto finish;
    }

    result = ENOMEM;

    _gKextutilLock = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, client,
                        DISPATCH_MACH_SEND_DEAD, dispatch_get_main_queue());

    if (_gKextutilLock) {
    
        dispatch_source_set_event_handler(_gKextutilLock, ^{
                OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogIPCFlag,
                    "Client exited without releasing kextutil lock.");
                removeKextutilLock();
            });
    
        dispatch_source_set_cancel_handler(_gKextutilLock, ^{
                dispatch_release(_gKextutilLock);
                mach_port_deallocate(mach_task_self(), client);
                _gKextutilLock = NULL;
            });
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
/*********************************************************************
* We used to require that all listed kernel components load, but
* nowadays we can get them from userland so we only try to load the
* ones we have. If an error occurs later, such is life.
*
* Note that we look the kexts up first, so we can avoid spurious
* (in this context, anyhow) log messages about kexts not being found.
*
* xxx - do we even need to do this any more? Check if the kernel
* xxx - compoonents just load in the regular paths
*********************************************************************/
OSReturn
KLDBootstrap::loadKernelComponentKexts(void)
{
    OSReturn      result      = kOSReturnSuccess;  // optimistic
    OSKext      * theKext     = NULL;              // must release
    const char ** kextIDPtr   = NULL;              // do not release

    for (kextIDPtr = &sKernelComponentNames[0]; *kextIDPtr; kextIDPtr++) {
        
        OSSafeReleaseNULL(theKext);
        theKext = OSKext::lookupKextWithIdentifier(*kextIDPtr);

        if (theKext) {
            if (kOSReturnSuccess != OSKext::loadKextWithIdentifier(
                *kextIDPtr, /* allowDefer */ false)) {

                // xxx - check KextBookkeeping, might be redundant
                OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel |
                    kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
                    "Failed to initialize kernel component %s.", *kextIDPtr);
                result = kOSReturnError;
            }
        }
    }

    OSSafeReleaseNULL(theKext);
    return result;
}
Exemplo n.º 8
0
void filterKextID(const void * vValue, void * vContext)
{
    CFStringRef       kextID  = (CFStringRef)vValue;
    FilterIDContext * context = (FilterIDContext *)vContext;
    OSKextRef         theKext = OSKextGetKextWithIdentifier(kextID);

    if (!theKext) {
        char kextIDCString[KMOD_MAX_NAME];

        CFStringGetCString(kextID, kextIDCString, sizeof(kextIDCString),
            kCFStringEncodingUTF8);
            
        if (context->optional) {
            OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                    "Can't find kext with optional identifier %s; skipping.", kextIDCString);
        } else {
            OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                    "Error - can't find kext with identifier %s.", kextIDCString);
            context->error = TRUE;
        }

        goto finish;
    }

    if (checkKextForProblems(context->toolArgs, theKext, context->arch)) {
        if (!context->optional) {
            OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 
                    "Error - a required kext was omitted");
            context->error = true;
        }
        goto finish;
    }

    if (!CFArrayContainsValue(context->kextArray,
            RANGE_ALL(context->kextArray), theKext)) 
    {
        CFArrayAppendValue(context->kextArray, theKext);
    }

finish:
    return;    
}
Exemplo n.º 9
0
ExitStatus setPrelinkedKernelArgs(
    KcgenArgs * toolArgs,
    char      * filename)
{
    ExitStatus          result          = EX_USAGE;

    if (toolArgs->prelinkedKernelPath) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogWarningLevel | kOSKextLogGeneralFlag,
            "Warning - prelinked kernel already specified; using last.");
    } else {
        toolArgs->prelinkedKernelPath = malloc(PATH_MAX);
        if (!toolArgs->prelinkedKernelPath) {
            OSKextLogMemError();
            result = EX_OSERR;
            goto finish;
        }
    }

   /* If we don't have a filename we construct a default one, automatically
    * add the system extensions folders, and note that we're using default
    * info.
    */
    if (!filename) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Error - prelinked kernel filename required");
        goto finish;
    } else {
        size_t len = strlcpy(toolArgs->prelinkedKernelPath, filename, PATH_MAX);
        if (len >= PATH_MAX) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                "Error - prelinked kernel filename length exceeds PATH_MAX");
            goto finish;
        }
    }

    result = EX_OK;
finish:
    return result;
}
Exemplo n.º 10
0
ExitStatus checkArgs(KcgenArgs * toolArgs)
{
    ExitStatus  result  = EX_USAGE;

    if (!toolArgs->prelinkedKernelPath) 
    {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Error - no work to do; check options and try again.");
        goto finish;
    }
    
    if (!CFArrayGetCount(toolArgs->argURLs) &&
        !toolArgs->compress && !toolArgs->uncompress) 
    {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Error - no kexts or directories specified.");
        goto finish;
    }

    if (!toolArgs->compress && !toolArgs->uncompress) {
        toolArgs->compress = true;
    } else if (toolArgs->compress && toolArgs->uncompress) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Both -%s and -%s specified; using -%s.",
            kOptNameCompressed, kOptNameUncompressed, kOptNameCompressed);
        toolArgs->compress = true;
        toolArgs->uncompress = false;
    }
    
    result = EX_OK;

finish:
    if (result == EX_USAGE) {
        usage(kUsageLevelBrief);
    }
    return result;
}
Exemplo n.º 11
0
OSReturn
KLDBootstrap::readMkextExtensions(
    OSString   * deviceTreeName,
    OSData     * booterData)
{
    OSReturn result = kOSReturnError;

    uint32_t          checksum;
    IORegistryEntry * registryRoot = NULL;  // do not release
    OSData          * checksumObj  = NULL;   // must release

    OSKextLog(/* kext */ NULL,
        kOSKextLogStepLevel |
        kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
        "Reading startup mkext archive from device tree entry %s.",
        deviceTreeName->getCStringNoCopy());

   /* If we successfully read the archive,
    * then save the mkext's checksum in the IORegistry.
    * assumes we'll only ever have one mkext to boot
    */
    result = OSKext::readMkextArchive(booterData, &checksum);
    if (result == kOSReturnSuccess) {

        OSKextLog(/* kext */ NULL,
            kOSKextLogProgressLevel |
            kOSKextLogArchiveFlag,
            "Startup mkext archive has checksum 0x%x.", (int)checksum);

        registryRoot = IORegistryEntry::getRegistryRoot();
        assert(registryRoot);
        checksumObj = OSData::withBytes((void *)&checksum, sizeof(checksum));
        assert(checksumObj);
        if (checksumObj) {
            registryRoot->setProperty(kOSStartupMkextCRC, checksumObj);
        }
    }
    
    return result;
}
Exemplo n.º 12
0
Boolean getKextAddressAndSize(CFDictionaryRef infoDict, uint64_t *addr, uint64_t *size)
{
    Boolean     result     = FALSE;
    CFNumberRef scratchNum = NULL;  // do not release

    scratchNum = CFDictionaryGetValue(infoDict, CFSTR(kPrelinkExecutableSourceKey));
    if (!scratchNum) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Cannot find kext load address");
        goto finish;
    }

    if (!CFNumberGetValue(scratchNum, kCFNumberSInt64Type, addr)) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Cannot convert kext load address");
        goto finish;
    }

    scratchNum = CFDictionaryGetValue(infoDict, CFSTR(kPrelinkExecutableSizeKey));
    if (!scratchNum) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Cannot find kext size\n");
        goto finish;
    }

    if (!CFNumberGetValue(scratchNum, kCFNumberSInt64Type, size)) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Cannot convert kext size\n");
        goto finish;
    }

    result = TRUE;

finish:
    return result;
}
Exemplo n.º 13
0
void
OSMetaClass::instanceDestructed() const
{
    if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) {
        superClassLink->instanceDestructed();
    }

    if (((int)instanceCount) < 0) {
        OSKext * myKext = (OSKext *)reserved;

        OSKextLog(myKext, kOSMetaClassLogSpec,
            // xxx - this phrasing is rather cryptic
            "OSMetaClass: Class %s - bad retain (%d)",
            getClassName(), instanceCount);
    }
}
Exemplo n.º 14
0
/*********************************************************************
* The core constructor for a MetaClass (defined with this name always
* but within the scope of its represented class).
*
* MetaClass constructors are invoked in OSRuntimeInitializeCPP(),
* in between calls to OSMetaClass::preModLoad(), which sets up for
* registration, and OSMetaClass::postModLoad(), which actually
* records all the class/kext relationships of the new MetaClasses.
*********************************************************************/
OSMetaClass::OSMetaClass(
    const char        * inClassName,
    const OSMetaClass * inSuperClass,
    unsigned int        inClassSize)
{
    instanceCount = 0;
    classSize = inClassSize;
    superClassLink = inSuperClass;

   /* Hack alert: We are just casting inClassName and storing it in
    * an OSString * instance variable. This may be because you can't
    * create C++ objects in static constructors, but I really don't know!
    */
    className = (const OSSymbol *)inClassName;

    // sStalledClassesLock taken in preModLoad
    if (!sStalled) {
       /* There's no way we can look up the kext here, unfortunately.
        */
        OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
            "OSMetaClass: preModLoad() wasn't called for class %s "
            "(runtime internal error).",
            inClassName);
    } else if (!sStalled->result) {
        // Grow stalled array if neccessary
        if (sStalled->count >= sStalled->capacity) {
            OSMetaClass **oldStalled = sStalled->classes;
            int oldSize = sStalled->capacity * sizeof(OSMetaClass *);
            int newSize = oldSize
                + kKModCapacityIncrement * sizeof(OSMetaClass *);

            sStalled->classes = (OSMetaClass **)kalloc(newSize);
            if (!sStalled->classes) {
                sStalled->classes = oldStalled;
                sStalled->result = kOSMetaClassNoTempData;
                return;
            }

            sStalled->capacity += kKModCapacityIncrement;
            memmove(sStalled->classes, oldStalled, oldSize);
            kfree(oldStalled, oldSize);
            ACCUMSIZE(newSize - oldSize);
        }

        sStalled->classes[sStalled->count++] = this;
    }
}
Exemplo n.º 15
0
static void
OSMetaClassLogErrorForKext(
    OSReturn   error,
    OSKext   * aKext)
{
    const char * message = NULL;

    switch (error) {
    case kOSReturnSuccess:
        return;
    case kOSMetaClassNoInit:  // xxx - never returned; logged at fail site
        message = "OSMetaClass: preModLoad() wasn't called (runtime internal error).";
        break;
    case kOSMetaClassNoDicts:
        message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries.";
        break;
    case kOSMetaClassNoKModSet:
        message = "OSMetaClass: Allocation failure for internal kext recording set/set missing.";
        break;
    case kOSMetaClassNoInsKModSet:
        message = "OSMetaClass: Failed to record class in kext.";
        break;
    case kOSMetaClassDuplicateClass:
        message = "OSMetaClass: Duplicate class encountered.";
        break;
    case kOSMetaClassNoSuper:  // xxx - never returned
        message = "OSMetaClass: Can't associate a class with its superclass.";
        break;
    case kOSMetaClassInstNoSuper:  // xxx - never returned
        message = "OSMetaClass: Instance construction error; unknown superclass.";
        break;
    case kOSMetaClassNoKext:
        message = "OSMetaClass: Kext not found for metaclass.";
        break;
    case kOSMetaClassInternal:
    default:
        message = "OSMetaClass: Runtime internal error.";
        break;
    }

    if (message) {
        OSKextLog(aKext, kOSMetaClassLogSpec, "%s", message);
    }
    return;
}
Exemplo n.º 16
0
/*******************************************************************************
* XXX: I'm really not sure this is completely reliable for getting a relative
* XXX: path.
*******************************************************************************/
CFStringRef copyKextInfoDictionaryPath(
    OSKextRef theKext,
    PathSpec  pathSpec)
{
    CFStringRef   result      = NULL;
    CFURLRef      kextURL     = NULL;  // do not release
    CFURLRef      kextAbsURL  = NULL;  // must release
    CFBundleRef   kextBundle  = NULL;  // must release
    CFURLRef      infoDictURL = NULL;  // must release

    kextURL = OSKextGetURL(theKext);
    if (!kextURL) {
        OSKextLog(theKext,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Kext has no URL!");
        goto finish;
    }
    kextAbsURL = CFURLCopyAbsoluteURL(kextURL);
    if (!kextAbsURL) {
        OSKextLogMemError();
        goto finish;
    }

    kextBundle = CFBundleCreate(kCFAllocatorDefault, kextAbsURL);
    if (!kextBundle) {
        OSKextLogMemError();
        goto finish;
    }
    infoDictURL = _CFBundleCopyInfoPlistURL(kextBundle);
    if (!infoDictURL) {
        // not able to determine error here, bundle might have no plist
        // (well, we should never have gotten here if that were the case)
        result = CFStringCreateWithCString(kCFAllocatorDefault, "",
            kCFStringEncodingUTF8);
        goto finish;
    }

    result = copyAdjustedPathForURL(theKext, infoDictURL, pathSpec);

finish:
    SAFE_RELEASE(infoDictURL);
    SAFE_RELEASE(kextBundle);
    SAFE_RELEASE(kextAbsURL);
    return result;
}
Exemplo n.º 17
0
/*******************************************************************************
* XXX: I'm really not sure this is completely reliable for getting a relative
* XXX: path.
*******************************************************************************/
CFStringRef copyKextExecutablePath(
    OSKextRef theKext,
    PathSpec  pathSpec)
{
    CFStringRef   result = NULL;
    CFURLRef      kextURL       = NULL;  // do not release
    CFURLRef      kextAbsURL    = NULL;  // must release
    CFURLRef      executableURL = NULL;    // must release

    kextURL = OSKextGetURL(theKext);
    if (!kextURL) {
        OSKextLog(theKext,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Kext has no URL!");
        goto finish;
    }
    kextAbsURL = CFURLCopyAbsoluteURL(kextURL);
    if (!kextAbsURL) {
        OSKextLogMemError();
        goto finish;
    }

    executableURL = _CFBundleCopyExecutableURLInDirectory(kextAbsURL);
    if (!executableURL) {
        // not able to determine error here, bundle might have no executable
        result = CFStringCreateWithCString(kCFAllocatorDefault, "",
            kCFStringEncodingUTF8);
        goto finish;
    }
    result = copyAdjustedPathForURL(theKext, executableURL, pathSpec);

finish:
    SAFE_RELEASE(executableURL);
    SAFE_RELEASE(kextAbsURL);
    return result;
}
Exemplo n.º 18
0
/*******************************************************************************
* copyAdjustedPathForURL()
*
* This function takes an URL with a given kext, and adjusts it to be absolute
* or relative to the kext's containing repository, properly handling plugin
* kexts to include the repository-path of the containing kext as well.
*******************************************************************************/
CFStringRef copyAdjustedPathForURL(
    OSKextRef theKext,
    CFURLRef  urlToAdjust,
    PathSpec  pathSpec)
{
    CFStringRef result       = NULL;
    CFURLRef    absURL       = NULL;  // must release
    CFStringRef absPath      = NULL;  // must release
    CFStringRef kextAbsPath  = NULL;  // must release
    CFStringRef kextRelPath  = NULL;  // must release
    CFStringRef pathInKext   = NULL;  // must release
    CFRange     scratchRange;

    if (pathSpec != kPathsFull && pathSpec != kPathsRelative) {
        OSKextLog(theKext,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Invalid argument to copyAdjustedPathForURL().");
    }

    absURL = CFURLCopyAbsoluteURL(urlToAdjust);
    if (!absURL) {
        OSKextLogMemError();
        goto finish;
    }

    if (pathSpec == kPathsFull) {
        result = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
        goto finish;
    }

   /*****
    * Okay, we are doing repository-relative paths here. Here's how!
    * We are strip the matching part of the kext's absolute path
    * from the URL/path handed in, which gives us the path in the kext.
    * Then we tack that back onto the kext's repository-relative path. Got it?
    */

    kextAbsPath = copyPathForKext(theKext, kPathsFull);
    kextRelPath = copyPathForKext(theKext, kPathsRelative);
    absPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
    if (!kextAbsPath || !kextRelPath || !absPath) {
        goto finish;
    }

    scratchRange = CFRangeMake(CFStringGetLength(kextAbsPath),
        CFStringGetLength(absPath) - CFStringGetLength(kextAbsPath));
    pathInKext = CFStringCreateWithSubstring(kCFAllocatorDefault, absPath,
        scratchRange);
    if (!pathInKext) {
        OSKextLogMemError();
    }
    result = CFStringCreateWithFormat(kCFAllocatorDefault, /* options */ 0,
        CFSTR("%@%@"), kextRelPath, pathInKext);
    
finish:
    SAFE_RELEASE(absURL);
    SAFE_RELEASE(absPath);
    SAFE_RELEASE(kextAbsPath);
    SAFE_RELEASE(kextRelPath);
    SAFE_RELEASE(pathInKext);
    return result;
}
Exemplo n.º 19
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;
}
Exemplo n.º 20
0
void
KLDBootstrap::loadKernelExternalComponents(void)
{
    OSDictionary         * extensionsDict = NULL;  // must release
    OSCollectionIterator * keyIterator    = NULL;  // must release
    OSString             * bundleID       = NULL;  // don't release
    OSKext               * theKext        = NULL;  // don't release
    OSBoolean            * isKernelExternalComponent = NULL;  // don't release

    OSKextLog(/* kext */ NULL,
        kOSKextLogStepLevel |
        kOSKextLogLoadFlag,
        "Loading Kernel External Components.");

    extensionsDict = OSKext::copyKexts();
    if (!extensionsDict) {
        return;
    }

    keyIterator = OSCollectionIterator::withCollection(extensionsDict);
    if (!keyIterator) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag,
            "Failed to allocate iterator for Kernel External Components.");
        goto finish;
    }

    while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) {

        const char * bundle_id = bundleID->getCStringNoCopy();
        
       /* Skip extensions whose bundle IDs don't start with "com.apple.kec.".
        */
        if (!bundle_id ||
            (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) {

            continue;
        }

        theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID));
        if (!theKext) {
            continue;
        }

        isKernelExternalComponent = OSDynamicCast(OSBoolean,
            theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey));
        if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogStepLevel |
                kOSKextLogLoadFlag,
                "Loading kernel external component %s.", bundleID->getCStringNoCopy());
            OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(),
                /* allowDefer */ false);
        }
    }

finish:
    OSSafeReleaseNULL(keyIterator);
    OSSafeReleaseNULL(extensionsDict);

    return;
}
Exemplo n.º 21
0
void
KLDBootstrap::readBooterExtensions(void)
{
    IORegistryEntry           * booterMemoryMap         = NULL;  // must release
    OSDictionary              * propertyDict            = NULL;  // must release
    OSCollectionIterator      * keyIterator             = NULL;  // must release
    OSString                  * deviceTreeName          = NULL;  // do not release
    
    const _DeviceTreeBuffer   * deviceTreeBuffer        = NULL;  // do not free
    char                      * booterDataPtr           = NULL;  // do not free
    OSData                    * booterData              = NULL;  // must release

    OSKext                    * aKext                   = NULL;  // must release

    OSKextLog(/* kext */ NULL,
        kOSKextLogProgressLevel |
        kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
        "Reading startup extensions from booter memory.");
    
    booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);

    if (!booterMemoryMap) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
            "Can't read booter memory map.");
        goto finish;
    }

    propertyDict = booterMemoryMap->dictionaryWithProperties();
    if (!propertyDict) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogDirectoryScanFlag,
            "Can't get property dictionary from memory map.");
        goto finish;
    }

    keyIterator = OSCollectionIterator::withCollection(propertyDict);
    if (!keyIterator) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag,
            "Can't allocate iterator for driver images.");
        goto finish;
    }

    /* Create dictionary of excluded kexts
     */
    OSKext::createExcludeListFromBooterData(propertyDict, keyIterator);
    keyIterator->reset();

    while ( ( deviceTreeName =
        OSDynamicCast(OSString, keyIterator->getNextObject() ))) {

        const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
        OSData * deviceTreeEntry = OSDynamicCast(OSData,
            propertyDict->getObject(deviceTreeName));

       /* Clear out the booterData from the prior iteration.
        */
        OSSafeReleaseNULL(booterData);

        /* If there is no entry for the name, we can't do much with it. */
        if (!deviceTreeEntry) {
            continue;
        }

        /* Make sure it is a kext */
        if (strncmp(devTreeNameCString,
                    BOOTER_KEXT_PREFIX,
                    CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
            continue;
        }

        deviceTreeBuffer = (const _DeviceTreeBuffer *)
            deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
        if (!deviceTreeBuffer) {
           /* We can't get to the data, so we can't do anything,
            * not even free it from physical memory (if it's there).
            */
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogDirectoryScanFlag,
                "Device tree entry %s has NULL pointer.",
                devTreeNameCString);
            goto finish;  // xxx - continue, panic?
        }

        booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
        if (!booterDataPtr) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogDirectoryScanFlag,
                "Can't get virtual address for device tree entry %s.",
                devTreeNameCString);
            goto finish;
        }

       /* Wrap the booter data buffer in an OSData and set a dealloc function
        * so it will take care of the physical memory when freed. Kexts will
        * retain the booterData for as long as they need it. Remove the entry
        * from the booter memory map after this is done.
        */
        booterData = OSData::withBytesNoCopy(booterDataPtr,
            deviceTreeBuffer->length);
        if (!booterData) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogGeneralFlag,
                "Error - Can't allocate OSData wrapper for device tree entry %s.",
                devTreeNameCString);
            goto finish;
        }
        booterData->setDeallocFunction(osdata_phys_free);

        /* 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::withBooterData(deviceTreeName, booterData);
        OSSafeReleaseNULL(newKext);

        booterMemoryMap->removeProperty(deviceTreeName);

    } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */

finish:

    OSSafeReleaseNULL(booterMemoryMap);
    OSSafeReleaseNULL(propertyDict);
    OSSafeReleaseNULL(keyIterator);
    OSSafeReleaseNULL(booterData);
    OSSafeReleaseNULL(aKext);
    return;
}
Exemplo n.º 22
0
void
KLDBootstrap::readPrelinkedExtensions(
    kernel_section_t * prelinkInfoSect)
{
    OSArray                   * infoDictArray           = 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

    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
    vm_size_t                   prelinkLength           = 0;


    OSDictionary              * infoDict                = NULL;  // do not release

    IORegistryEntry           * registryRoot            = NULL;  // do not release
    OSNumber                  * prelinkCountObj         = NULL;  // must release

    u_int                       i = 0;
#if NO_KEXTD
    bool                        ramDiskBoot;
    bool                        developerDevice;
    bool                        dontLoad;
#endif
    OSData                     * kaslrOffsets = NULL;
    unsigned long               plk_segSizes[PLK_SEGMENTS];
    vm_offset_t                 plk_segAddrs[PLK_SEGMENTS];

    OSKextLog(/* kext */ NULL,
        kOSKextLogProgressLevel |
        kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
        "Starting from prelinked kernel.");

    prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
    if (!prelinkTextSegment) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
            "Can't find prelinked kexts' text segment.");
        goto finish;
    }

#if KASLR_KEXT_DEBUG
    unsigned long   scratchSize;
    vm_offset_t     scratchAddr;
    
    IOLog("kaslr: prelinked kernel address info: \n");
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
#endif

    prelinkData = (void *) prelinkTextSegment->vmaddr;
    prelinkLength = prelinkTextSegment->vmsize;

    /* build arrays of plk info for later use */
    const char ** segNamePtr;

    for (segNamePtr = &plk_segNames[0], i = 0; *segNamePtr && i < PLK_SEGMENTS; segNamePtr++, i++) {
        plk_segSizes[i] = 0;
        plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(&_mh_execute_header, *segNamePtr, &plk_segSizes[i]);
    }


   /* 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;
    }

#if NO_KEXTD
    /* Check if we should keep developer kexts around.
     * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
     */
    developerDevice = true;
    PE_parse_boot_argn("developer", &developerDevice, sizeof(developerDevice));

    ramDiskBoot = IORamDiskBSDRoot();
#endif /* NO_KEXTD */


    infoDictArray = OSDynamicCast(OSArray, 
        prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey));
    if (!infoDictArray) {
        OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
            "The prelinked kernel has no kext info dictionaries");
        goto finish;
    }
    
    /* kaslrOffsets are available use them to slide local relocations */
    kaslrOffsets = OSDynamicCast(OSData,
                                 prelinkInfoDict->getObject(kPrelinkLinkKASLROffsetsKey));
        
    /* Create dictionary of excluded kexts
     */
    OSKext::createExcludeListFromPrelinkInfo(infoDictArray);
    /* 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;
        }

#if NO_KEXTD
        dontLoad = false;

        /* If we're not on a developer device, skip and free developer kexts.
         */
        if (developerDevice == false) {
            OSBoolean *devOnlyBool = OSDynamicCast(OSBoolean,
                infoDict->getObject(kOSBundleDeveloperOnlyKey));
            if (devOnlyBool == kOSBooleanTrue) {
                dontLoad = true;
            }
        }

        /* Skip and free kexts that are only needed when booted from a ram disk.
         */
        if (ramDiskBoot == false) {
            OSBoolean *ramDiskOnlyBool = OSDynamicCast(OSBoolean,
                infoDict->getObject(kOSBundleRamDiskOnlyKey));
            if (ramDiskOnlyBool == kOSBooleanTrue) {
                dontLoad = true;
            }
        }

        if (dontLoad == true) {
            OSString *bundleID = OSDynamicCast(OSString,
                infoDict->getObject(kCFBundleIdentifierKey));
            if (bundleID) {
                OSKextLog(NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag,
                    "Kext %s not loading.", bundleID->getCStringNoCopy());
            }
            
            OSNumber *addressNum = OSDynamicCast(OSNumber,
                infoDict->getObject(kPrelinkExecutableLoadKey));
            OSNumber *lengthNum = OSDynamicCast(OSNumber,
                infoDict->getObject(kPrelinkExecutableSizeKey));
            if (addressNum && lengthNum) {
#error Pick the right way to free prelinked data on this arch
            }

            infoDictArray->removeObject(i--);
            continue;
        }
#endif /* NO_KEXTD */

       /* 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, (kaslrOffsets ? TRUE : FALSE));
        OSSafeReleaseNULL(newKext);
    }

    /* slide kxld relocations */
    if (kaslrOffsets && vm_kernel_slide > 0) {
	    int slidKextAddrCount = 0;
	    int badSlideAddr = 0;
	    int badSlideTarget = 0;

        kaslrPackedOffsets * myOffsets = NULL;
	    myOffsets = (kaslrPackedOffsets *) kaslrOffsets->getBytesNoCopy();

	    for (uint32_t j = 0; j < myOffsets->count; j++) {

		    uint64_t        slideOffset = (uint64_t) myOffsets->offsetsArray[j];
		    uintptr_t *     slideAddr = (uintptr_t *) ((uint64_t)prelinkData + slideOffset);
		    int             slideAddrSegIndex = -1;
		    int             addrToSlideSegIndex = -1;

		    slideAddrSegIndex = __whereIsAddr( (vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], PLK_SEGMENTS );
		    if (slideAddrSegIndex >= 0) {
			    addrToSlideSegIndex = __whereIsAddr( (vm_offset_t)(*slideAddr + vm_kernel_slide), &plk_segSizes[0], &plk_segAddrs[0], PLK_SEGMENTS );
			    if (addrToSlideSegIndex < 0) {
				    badSlideTarget++;
				    continue;
			    }
		    }
		    else {
			    badSlideAddr++;
			    continue;
		    }

		    slidKextAddrCount++;
		    *(slideAddr) += vm_kernel_slide;
	    } // for ...

	    /* All kexts are now slid, set VM protections for them */
	    OSKext::setAllVMAttributes();
    }

   /* 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);
    }
    
    OSKextLog(/* kext */ NULL,
        kOSKextLogProgressLevel |
        kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
        kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
        "%u prelinked kexts", 
        infoDictArray->getCount());

#if CONFIG_KEXT_BASEMENT
        /* On CONFIG_KEXT_BASEMENT 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 /* __x86_64__ */

   /* 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:
    OSSafeReleaseNULL(errorString);
    OSSafeReleaseNULL(parsedXML);
    OSSafeReleaseNULL(theKernel);
    OSSafeReleaseNULL(prelinkCountObj);
    return;
}
Exemplo n.º 23
0
ExitStatus printKextInfo(KctoolArgs * toolArgs)
{
    ExitStatus result         = EX_SOFTWARE;
    CFArrayRef kextPlistArray = NULL;
    CFIndex    i, count;
    
    if (CFArrayGetTypeID() == CFGetTypeID(toolArgs->kernelcacheInfoPlist)) {
        kextPlistArray = (CFArrayRef)toolArgs->kernelcacheInfoPlist;
    } else if (CFDictionaryGetTypeID() == CFGetTypeID(toolArgs->kernelcacheInfoPlist)){
        kextPlistArray = (CFArrayRef)CFDictionaryGetValue(toolArgs->kernelcacheInfoPlist,
            CFSTR("_PrelinkInfoDictionary"));
    } else {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Unrecognized kernelcache plist data.");
        goto finish;
    }
    
    count = CFArrayGetCount(kextPlistArray);
    for (i = 0; i < count; i++) {
        CFDictionaryRef kextInfoDict = (CFDictionaryRef)CFArrayGetValueAtIndex(kextPlistArray, i);
        CFStringRef     thisKextID = CFDictionaryGetValue(kextInfoDict, kCFBundleIdentifierKey);
        
        if (thisKextID && CFEqual(thisKextID, toolArgs->kextID)) {
            uint64_t      kextAddr   = 0;
            uint64_t      kextSize   = 0;
            u_long        kextOffset = 0;
            const UInt8 * kextMachO  = NULL;  // do not free
            void        * section    = NULL;  // do not free

            if (!getKextAddressAndSize(kextInfoDict, &kextAddr, &kextSize)) {
                goto finish;
            }

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                section = (void *)macho_get_section_by_name_64(
                    (struct mach_header_64 *)toolArgs->kernelcacheImageBytes,
                    kPrelinkTextSegment, kPrelinkTextSection);

            } else {
                section = (void *)macho_get_section_by_name(
                    (struct mach_header *)toolArgs->kernelcacheImageBytes,
                    kPrelinkTextSegment, kPrelinkTextSection);
            }

            if (!section) {
                OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                    "Cannot find %s,%s in kernelcache.",
                    kPrelinkTextSegment, kPrelinkTextSection);
                goto finish;
            }

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                kextOffset = ((struct section_64 *)section)->offset + (u_long)(kextAddr - ((struct section_64 *)section)->addr);
            } else {
                kextOffset = ((struct section *)section)->offset + (u_long)(kextAddr - ((struct section *)section)->addr);
            }
            kextMachO = toolArgs->kernelcacheImageBytes + kextOffset;

            /* Find the requested section's file offset and size */

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                section = (void *)macho_get_section_by_name_64(
                    (struct mach_header_64 *)kextMachO,
                    toolArgs->segmentName, toolArgs->sectionName);

            } else {
               /* macho_get_section_by_name doesn't work as the kexts don't have a __TEXT segment.
                * They just have a single segment named "" with all the sections dumped under it.
                */
                section = (void *)getSectionByName(
                    kextMachO,
                    toolArgs->segmentName, toolArgs->sectionName);
            }

            if (!section) {
                OSKextLogCFString(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                    CFSTR("Cannot find %s,%s in kext %@\n"),
                    toolArgs->segmentName, toolArgs->sectionName, toolArgs->kextID);
                goto finish;
            }

            if (ISMACHO64(MAGIC32(toolArgs->kernelcacheImageBytes))) {
                printf("%#llx %#lx %#llx\n",
                    ((struct section_64 *)section)->addr,
                    kextOffset + ((struct section_64 *)section)->offset,
                    ((struct section_64 *)section)->size);
            } else {
                printf("%#x %#lx %#x\n",
                    ((struct section *)section)->addr,
                    kextOffset + ((struct section *)section)->offset,
                    ((struct section *)section)->size);
            }

            result = EX_OK;
            break;
        }
    }

finish:
    return result;
}
Exemplo n.º 24
0
/*********************************************************************
* IMPORTANT: Once we have done the vm_map_copyout(), we *must* return
* KERN_SUCCESS or the kernel map gets messed up (reason as yet
* unknown). We use op_result to return the real result of our work.
*********************************************************************/
kern_return_t kext_request(
    host_priv_t                             hostPriv,
    /* in only */  uint32_t                 clientLogSpec,
    /* in only */  vm_offset_t              requestIn,
    /* in only */  mach_msg_type_number_t   requestLengthIn,
    /* out only */ vm_offset_t            * responseOut,
    /* out only */ mach_msg_type_number_t * responseLengthOut,
    /* out only */ vm_offset_t            * logDataOut,
    /* out only */ mach_msg_type_number_t * logDataLengthOut,
    /* out only */ kern_return_t          * op_result)
{
    kern_return_t     result          = KERN_FAILURE;
    vm_map_address_t  map_addr        = 0;     // do not free/deallocate
    char            * request         = NULL;  // must vm_deallocate

    mkext2_header   * mkextHeader     = NULL;  // do not release
    bool              isMkext         = false;

    char            * response        = NULL;  // must kmem_free
    uint32_t          responseLength  = 0;
    char            * logData         = NULL;  // must kmem_free
    uint32_t          logDataLength   = 0;

   /* MIG doesn't pass "out" parameters as empty, so clear them immediately
    * just in case, or MIG will try to copy out bogus data.
    */    
    *op_result = KERN_FAILURE;
    *responseOut = NULL;
    *responseLengthOut = 0;
    *logDataOut = NULL;
    *logDataLengthOut = 0;

   /* Check for input. Don't discard what isn't there, though.
    */
    if (!requestLengthIn || !requestIn) {
		OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogIPCFlag,
            "Invalid request from user space (no data).");
        *op_result = KERN_INVALID_ARGUMENT;
        goto finish;
    }

   /* Once we have done the vm_map_copyout(), we *must* return KERN_SUCCESS
    * or the kernel map gets messed up (reason as yet unknown). We will use
    * op_result to return the real result of our work.
    */
    result = vm_map_copyout(kernel_map, &map_addr, (vm_map_copy_t)requestIn);
    if (result != KERN_SUCCESS) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogIPCFlag,
            "vm_map_copyout() failed for request from user space.");
        vm_map_copy_discard((vm_map_copy_t)requestIn);
        goto finish;
    }
    request = CAST_DOWN(char *, map_addr);

   /* Check if request is an mkext; this is always a load request
    * and requires root access. If it isn't an mkext, see if it's
    * an XML request, and check the request to see if that requires
    * root access.
    */
    if (requestLengthIn > sizeof(mkext2_header)) {
        mkextHeader = (mkext2_header *)request;
        if (MKEXT_GET_MAGIC(mkextHeader) == MKEXT_MAGIC &&
            MKEXT_GET_SIGNATURE(mkextHeader) == MKEXT_SIGN) {

            isMkext = true;
        }
    }

    if (isMkext) {
#ifdef SECURE_KERNEL
        // xxx - something tells me if we have a secure kernel we don't even
        // xxx - want to log a message here. :-)
        *op_result = KERN_NOT_SUPPORTED;
        goto finish;
#else
        // xxx - can we find out if calling task is kextd?
        // xxx - can we find the name of the calling task?
        if (hostPriv == HOST_PRIV_NULL) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogLoadFlag | kOSKextLogIPCFlag,
                "Attempt by non-root process to load a kext.");
            *op_result = kOSKextReturnNotPrivileged;
            goto finish;
        }

        *op_result = OSKext::loadFromMkext((OSKextLogSpec)clientLogSpec,
            request, requestLengthIn,
            &logData, &logDataLength);

#endif /* defined(SECURE_KERNEL) */

    } else {

       /* If the request isn't an mkext, then is should be XML. Parse it
        * if possible and hand the request over to OSKext.
        */
        *op_result = OSKext::handleRequest(hostPriv,
            (OSKextLogSpec)clientLogSpec,
            request, requestLengthIn,
            &response, &responseLength,
            &logData, &logDataLength);
    }

    if (response && responseLength > 0) {
        kern_return_t copyin_result;

        copyin_result = vm_map_copyin(kernel_map,
            CAST_USER_ADDR_T(response), responseLength,
            /* src_destroy */ false, (vm_map_copy_t *)responseOut);
        if (copyin_result == KERN_SUCCESS) {
            *responseLengthOut = responseLength;
        } else {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogIPCFlag,
                "Failed to copy response to request from user space.");
            *op_result = copyin_result;  // xxx - should we map to our own code?
            *responseOut = NULL;
            *responseLengthOut = 0;
            goto finish;
        }
    }

    if (logData && logDataLength > 0) {
        kern_return_t copyin_result;

        copyin_result = vm_map_copyin(kernel_map,
            CAST_USER_ADDR_T(logData), logDataLength,
            /* src_destroy */ false, (vm_map_copy_t *)logDataOut);
        if (copyin_result == KERN_SUCCESS) {
            *logDataLengthOut = logDataLength;
        } else {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogIPCFlag,
                "Failed to copy log data for request from user space.");
            *op_result = copyin_result;  // xxx - should we map to our own code?
            *logDataOut = NULL;
            *logDataLengthOut = 0;
            goto finish;
        }
    }

finish:
    if (request) {
        (void)vm_deallocate(kernel_map, (vm_offset_t)request, requestLengthIn);
    }
    if (response) {
        kmem_free(kernel_map, (vm_offset_t)response, responseLength);
    }
    if (logData) {
        kmem_free(kernel_map, (vm_offset_t)logData, logDataLength);
    }

    return result;
}
Exemplo n.º 25
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;
}
Exemplo n.º 26
0
/*******************************************************************************
* Fork a process after a specified delay, and either wait on it to exit or
* leave it to run in the background.
*
* Returns -2 on spawn() failure, -1 on other failure, and depending on wait:
* wait: true - exit status of forked program
* wait: false - pid of background process
*******************************************************************************/
int fork_program(const char * argv0, char * const argv[], Boolean wait)
{
    int            result;
    int            spawn_result;
    pid_t          child_pid;
    int            child_status;
    int            normal_iopolicy = getiopolicy_np(IOPOL_TYPE_DISK,
                                                    IOPOL_SCOPE_PROCESS);
    char ** environ = *(_NSGetEnviron());

    if (!wait) {
        setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE);
    }

    spawn_result = posix_spawn(&child_pid, argv0, /* file_actions */ NULL,
        /* spawnattrs */ NULL, argv, environ);

    // If we couldn't spawn the process, return -2 with errno for detail
    if (spawn_result != 0) {
        OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel,
            "posix_spawn failed for %s.", argv0);
        errno = spawn_result;
        result = -2;
        goto finish;
    }

    OSKextLog(/* kext */ NULL, kOSKextLogDetailLevel,
              "started child process %s[%d] (%ssynchronous).",
              argv0, child_pid, wait ? "" : "a");

    if (wait) {
        OSKextLogSpec logSpec = kOSKextLogDetailLevel;
        if (waitpid(child_pid, &child_status, 0) == -1) {
            result = -1;
            goto finish;
        }
        if (WIFEXITED(child_status)) {
            result = WEXITSTATUS(child_status);
            if (result) {
                logSpec = kOSKextLogErrorLevel;
            }
            OSKextLog(/* kext */ NULL, logSpec,
                "Child process %s[%d] exited with status %d.",
                argv0, child_pid, result);
        } else if (WIFSIGNALED(child_status)) {
            result = WTERMSIG(child_status);
            logSpec = kOSKextLogErrorLevel;
            OSKextLog(/* kext */ NULL, logSpec,
                "Child process %s[%d] exited due to signal %d.",
                argv0, child_pid, result);
        } else {
            // shouldn't be any other types of exit
            result = -1;
        }
    } else {
        result = child_pid;
    }

finish:
    setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, normal_iopolicy);
    
    return result;
}
Exemplo n.º 27
0
OSReturn
OSMetaClass::postModLoad(void * loadHandle)
{
    OSReturn         result     = kOSReturnSuccess;
    OSSymbol       * myKextName = 0;  // must release
    OSKext         * myKext     = 0;  // must release

    if (!sStalled || loadHandle != sStalled) {
        result = kOSMetaClassInternal;
        goto finish;
    }
    
    if (sStalled->result) {
        result = sStalled->result;
    } else switch (sBootstrapState) {

        case kNoDictionaries:
            sBootstrapState = kMakingDictionaries;
            // No break; fall through
            
        case kMakingDictionaries:
            sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
            if (!sAllClassesDict) {
                result = kOSMetaClassNoDicts;
                break;
            }

        // No break; fall through

        case kCompletedBootstrap:
        {
            unsigned int i;
            myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy(
                sStalled->kextIdentifier));
            
            if (!sStalled->count) {
                break;  // Nothing to do so just get out
            }
            
            myKext = OSKext::lookupKextWithIdentifier(myKextName);
            if (!myKext) {
                result = kOSMetaClassNoKext;

               /* Log this error here so we can include the kext name.
                */
                OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
                    "OSMetaClass: Can't record classes for kext %s - kext not found.",
                    sStalled->kextIdentifier);
                break;
            }
            
           /* First pass checking classes aren't already loaded. If any already
            * exist, we don't register any, and so we don't technically have
            * to do any C++ teardown.
            *
            * Hack alert: me->className has been a C string until now.
            * We only release the OSSymbol if we store the kext.
            */
            IOLockLock(sAllClassesLock);
            for (i = 0; i < sStalled->count; i++) {
                OSMetaClass * me = sStalled->classes[i];
                OSMetaClass * orig = OSDynamicCast(OSMetaClass,
                    sAllClassesDict->getObject((const char *)me->className));
                
                if (orig) {

                   /* Log this error here so we can include the class name.
                    * xxx - we should look up the other kext that defines the class
                    */
                    OSKextLog(myKext, kOSMetaClassLogSpec,
                        "OSMetaClass: Kext %s class %s is a duplicate;"
                        "kext %s already has a class by that name.",
                         sStalled->kextIdentifier, (const char *)me->className,
                        ((OSKext *)orig->reserved)->getIdentifierCString());
                    result = kOSMetaClassDuplicateClass;
                    break;
                }
            }
            IOLockUnlock(sAllClassesLock);
            
           /* Bail if we didn't go through the entire list of new classes
            * (if we hit a duplicate).
            */
            if (i != sStalled->count) {
                break;
            }

            // Second pass symbolling strings and inserting classes in dictionary
            IOLockLock(sAllClassesLock);
            for (i = 0; i < sStalled->count; i++) {
                OSMetaClass * me = sStalled->classes[i];
                
               /* Hack alert: me->className has been a C string until now.
                * We only release the OSSymbol in ~OSMetaClass()
                * if we set the reference to the kext.
                */
                me->className = 
                    OSSymbol::withCStringNoCopy((const char *)me->className);

                // xxx - I suppose if these fail we're going to panic soon....
                sAllClassesDict->setObject(me->className, me);
                
               /* Do not retain the kext object here.
                */
                me->reserved = (ExpansionData *)myKext;
                if (myKext) {
                    result = myKext->addClass(me, sStalled->count);
                    if (result != kOSReturnSuccess) {
                       /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */
                        break;
                    }
                }
            }
            IOLockUnlock(sAllClassesLock);
            sBootstrapState = kCompletedBootstrap;
            break;
        }
            
        default:
            result = kOSMetaClassInternal;
            break;
    }
    
finish:
   /* Don't call logError() for success or the conditions logged above
    * or by called function.
    */
    if (result != kOSReturnSuccess &&
        result != kOSMetaClassNoInsKModSet &&
        result != kOSMetaClassDuplicateClass &&
        result != kOSMetaClassNoKext) {

        OSMetaClassLogErrorForKext(result, myKext);
    }

    OSSafeRelease(myKextName);
    OSSafeRelease(myKext);

    if (sStalled) {
        ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
            sizeof(*sStalled)));
        kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
        kfree(sStalled, sizeof(*sStalled));
        sStalled = 0;
    }
    
    IOLockUnlock(sStalledClassesLock);

    return result;
}
Exemplo n.º 28
0
ExitStatus readArgs(
    int            * argc,
    char * const  ** argv,
    KctoolArgs     * toolArgs)
{
    ExitStatus   result         = EX_USAGE;
    ExitStatus   scratchResult  = EX_USAGE;
    int          optchar        = 0;
    int          longindex      = -1;

    bzero(toolArgs, sizeof(*toolArgs));
    
    /*****
    * Process command line arguments.
    */
    while ((optchar = getopt_long_only(*argc, *argv,
        kOptChars, sOptInfo, &longindex)) != -1) {

        switch (optchar) {
  
            case kOptArch:
                toolArgs->archInfo = NXGetArchInfoFromName(optarg);
                if (!toolArgs->archInfo) {
                    OSKextLog(/* kext */ NULL,
                        kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                        "Unknown architecture %s.", optarg);
                    goto finish;
                }
                break;
  
            case kOptHelp:
                usage(kUsageLevelFull);
                result = kKctoolExitHelp;
                goto finish;
    
            default:
                OSKextLog(/* kext */ NULL,
                    kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                    "unrecognized option %s", (*argv)[optind-1]);
                goto finish;
                break;

        }
        
       /* Reset longindex, because getopt_long_only() is stupid and doesn't.
        */
        longindex = -1;
    }

   /* Update the argc & argv seen by main() so that boot<>root calls
    * handle remaining args.
    */
    *argc -= optind;
    *argv += optind;

    if (*argc != 4) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "incorrect number of arguments");
        goto finish;
    }

   /*****
    * Record remaining args from the command line.
    */
    toolArgs->kernelcachePath = (*argv)[0];
    toolArgs->kextID = CFStringCreateWithCString(kCFAllocatorDefault, (*argv)[1], kCFStringEncodingUTF8);
    if (!toolArgs->kextID) {
        OSKextLogMemError();
        result = EX_OSERR;
        goto finish;
    }
    toolArgs->segmentName = (*argv)[2];
    toolArgs->sectionName = (*argv)[3];

    result = EX_OK;

finish:
    if (result == EX_USAGE) {
        usage(kUsageLevelBrief);
    }
    
    return result;
}
Exemplo n.º 29
0
CFDataRef createMkext1ForArch(const NXArchInfo * arch, CFArrayRef archiveKexts,
    boolean_t compress)
{
    CFMutableDataRef       result            = NULL;
    CFMutableDictionaryRef kextsByIdentifier = NULL;
    Mkext1Context          context;
    mkext1_header        * mkextHeader       = NULL;  // do not free
    const uint8_t        * adler_point = 0;
    CFIndex count, i;

    result = CFDataCreateMutable(kCFAllocatorDefault, /* capaacity */ 0);
    if (!result || !createCFMutableDictionary(&kextsByIdentifier)) {
        OSKextLogMemError();
        goto finish;
    }

   /* mkext1 can only contain 1 kext for a given bundle identifier, so we
    * have to pick out the most recent versions.
    */
    count = CFArrayGetCount(archiveKexts);
    for (i = 0; i < count; i++) {
        OSKextRef   theKext = (OSKextRef)CFArrayGetValueAtIndex(archiveKexts, i);
        CFStringRef bundleIdentifier = OSKextGetIdentifier(theKext);
        OSKextRef   savedKext = (OSKextRef)CFDictionaryGetValue(kextsByIdentifier,
            bundleIdentifier);
        OSKextVersion thisVersion, savedVersion;


        if (!OSKextSupportsArchitecture(theKext, arch)) {
            continue;
        }

        if (!savedKext) {
            CFDictionarySetValue(kextsByIdentifier, bundleIdentifier, theKext);
            continue;
        }
        
        thisVersion = OSKextGetVersion(theKext);
        savedVersion = OSKextGetVersion(savedKext);
        
        if (thisVersion > savedVersion) {
            CFDictionarySetValue(kextsByIdentifier, bundleIdentifier, theKext);
        }
    }

   /* Add room for the mkext header and kext descriptors.
    */
    CFDataSetLength(result, sizeof(mkext1_header) +
        CFDictionaryGetCount(kextsByIdentifier) * sizeof(mkext_kext));

    context.mkext = result;
    context.kextIndex = 0;
    context.compressOffset = (uint32_t)CFDataGetLength(result);
    context.arch = arch;
    context.fatal = false;
    context.compress = compress;
    CFDictionaryApplyFunction(kextsByIdentifier, addToMkext1, &context);
    if (context.fatal) {
        SAFE_RELEASE_NULL(result);
        goto finish;
    }

    mkextHeader = (mkext1_header *)CFDataGetBytePtr(result);
    mkextHeader->magic = OSSwapHostToBigInt32(MKEXT_MAGIC);
    mkextHeader->signature = OSSwapHostToBigInt32(MKEXT_SIGN);
    mkextHeader->version = OSSwapHostToBigInt32(0x01008000);   // 'vers' 1.0.0
    mkextHeader->numkexts =
        OSSwapHostToBigInt32((__uint32_t)CFDictionaryGetCount(kextsByIdentifier));
    mkextHeader->cputype = OSSwapHostToBigInt32(arch->cputype);
    mkextHeader->cpusubtype = OSSwapHostToBigInt32(arch->cpusubtype);
    mkextHeader->length = OSSwapHostToBigInt32((__uint32_t)CFDataGetLength(result));

    adler_point = (UInt8 *)&mkextHeader->version;
    mkextHeader->adler32 = OSSwapHostToBigInt32(local_adler32(
        (UInt8 *)&mkextHeader->version,
        (int)(CFDataGetLength(result) - (adler_point - (uint8_t *)mkextHeader))));

    OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogArchiveFlag,
        "Created mkext for %s containing %lu kexts.",
        arch->name,
        CFDictionaryGetCount(kextsByIdentifier));

finish:
    SAFE_RELEASE(kextsByIdentifier);
    return result;
}
Exemplo n.º 30
0
int main(int argc, char * const argv[])
{
    ExitStatus           result             = EX_SOFTWARE;
    KctoolArgs           toolArgs;
    int                  kernelcache_fd     = -1;  // must close()
    void               * fat_header         = NULL;  // must unmapFatHeaderPage()
    struct fat_arch    * fat_arch           = NULL;
    CFDataRef            rawKernelcache     = NULL;  // must release
    CFDataRef            kernelcacheImage   = NULL;  // must release

    void               * prelinkInfoSect    = NULL;

    const char         * prelinkInfoBytes   = NULL;
    CFPropertyListRef    prelinkInfoPlist   = NULL;  // must release

    bzero(&toolArgs, sizeof(toolArgs));

   /*****
    * Find out what the program was invoked as.
    */
    progname = rindex(argv[0], '/');
    if (progname) {
        progname++;   // go past the '/'
    } else {
        progname = (char *)argv[0];
    }

   /* Set the OSKext log callback right away.
    */
    OSKextSetLogOutputFunction(&tool_log);

   /*****
    * Process args & check for permission to load.
    */
    result = readArgs(&argc, &argv, &toolArgs);
    if (result != EX_OK) {
        if (result == kKctoolExitHelp) {
            result = EX_OK;
        }
        goto finish;
    }

    kernelcache_fd = open(toolArgs.kernelcachePath, O_RDONLY);
    if (kernelcache_fd == -1) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't open %s: %s.", toolArgs.kernelcachePath, strerror(errno));
        result = EX_OSERR;
        goto finish;
    }
    fat_header = mapAndSwapFatHeaderPage(kernelcache_fd);
    if (!fat_header) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't map %s: %s.", toolArgs.kernelcachePath, strerror(errno));
        result = EX_OSERR;
        goto finish;
    }
    
    fat_arch = getFirstFatArch(fat_header);
    if (fat_arch && !toolArgs.archInfo) {
        toolArgs.archInfo = NXGetArchInfoFromCpuType(fat_arch->cputype, fat_arch->cpusubtype);
    }
    
    rawKernelcache = readMachOSliceForArch(toolArgs.kernelcachePath, toolArgs.archInfo,
        /* checkArch */ FALSE);
    if (!rawKernelcache) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't read arch %s from %s.", toolArgs.archInfo->name, toolArgs.kernelcachePath);
        goto finish;
    }

    if (MAGIC32(CFDataGetBytePtr(rawKernelcache)) == OSSwapHostToBigInt32('comp')) {
        kernelcacheImage = uncompressPrelinkedSlice(rawKernelcache);
        if (!kernelcacheImage) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
                "Can't uncompress kernelcache slice.");
            goto finish;
        }
    } else {
        kernelcacheImage = CFRetain(rawKernelcache);
    }

    toolArgs.kernelcacheImageBytes = CFDataGetBytePtr(kernelcacheImage);
    
    if (ISMACHO64(MAGIC32(toolArgs.kernelcacheImageBytes))) {
        prelinkInfoSect = (void *)macho_get_section_by_name_64(
            (struct mach_header_64 *)toolArgs.kernelcacheImageBytes,
            "__PRELINK_INFO", "__info");

    } else {
        prelinkInfoSect = (void *)macho_get_section_by_name(
            (struct mach_header *)toolArgs.kernelcacheImageBytes,
            "__PRELINK_INFO", "__info");
    }

    if (!prelinkInfoSect) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't find prelink info section.");
        goto finish;
    }

    if (ISMACHO64(MAGIC32(toolArgs.kernelcacheImageBytes))) {
        prelinkInfoBytes = ((char *)toolArgs.kernelcacheImageBytes) +
            ((struct section_64 *)prelinkInfoSect)->offset;
    } else {
        prelinkInfoBytes = ((char *)toolArgs.kernelcacheImageBytes) +
            ((struct section *)prelinkInfoSect)->offset;
    }

    toolArgs.kernelcacheInfoPlist = (CFPropertyListRef)IOCFUnserialize(prelinkInfoBytes,
        kCFAllocatorDefault, /* options */ 0, /* errorString */ NULL);
    if (!toolArgs.kernelcacheInfoPlist) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
            "Can't unserialize prelink info.");
        goto finish;
    }

    result = printKextInfo(&toolArgs);
    if (result != EX_OK) {
        goto finish;
    }

    result = EX_OK;

finish:

    SAFE_RELEASE(toolArgs.kernelcacheInfoPlist);
    SAFE_RELEASE(kernelcacheImage);
    SAFE_RELEASE(rawKernelcache);

    if (fat_header) {
        unmapFatHeaderPage(fat_header);
    }

    if (kernelcache_fd != -1) {
        close(kernelcache_fd);
    }
    return result;
}