1/*
2 * Copyright (c) 2000-2008 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#include <CoreFoundation/CoreFoundation.h>
24#include <Security/Authorization.h>
25#include <IOKit/IOKitLib.h>
26#include <IOKit/IOKitServer.h>
27#include <libc.h>
28#include <mach/mach.h>
29#include <mach/mach_host.h>
30#include <mach/bootstrap.h>
31#include <mach/kmod.h>
32#include <notify.h>
33#include <sys/proc_info.h>
34#include <libproc.h>
35#include <libgen.h>
36#include <bsm/libbsm.h>
37#include <servers/bootstrap.h>  // bootstrap mach ports
38#include <sandbox.h>
39#include <esp.h>
40
41#include <IOKit/kext/kextmanager_types.h>
42#include <IOKit/kext/OSKext.h>
43#include <IOKit/kext/OSKextPrivate.h>
44#include <IOKit/kext/KextManagerPriv.h>
45#include <System/libkern/kext_request_keys.h>
46
47#include "kext_tools_util.h"
48#include <bootfiles.h>
49#include "fork_program.h"
50#include "kextd_globals.h"
51#include "paths.h"
52#include "kextd_request.h"
53#include "kextd_main.h"
54#include "kextd_usernotification.h"
55
56#include "kextd_mach.h"  // mig-generated, not in project
57
58#include "bootcaches.h"
59#include "security.h"
60
61
62#define setCrashLogMessage(m)
63
64
65#define CRASH_INFO_KERNEL_KEXT_LOAD      "kernel kext load request: id %s"
66#define CRASH_INFO_KERNEL_KEXT_RESOURCE  "kext resource request: %s from id %s"
67#define CRASH_INFO_USER_KEXT_LOAD        "user kext load request: %s"
68#define CRASH_INFO_USER_KEXT_PATH        "user kext path request: %s"
69#define CRASH_INFO_USER_PROPERTY         "user kext property request: %s"
70
71kern_return_t sendPropertyValueResponse(
72    CFArrayRef    propertyValues,
73    char       ** xml_data_out,
74    int         * xml_data_length);
75void kextdProcessKernelLoadRequest(
76    CFDictionaryRef   request);
77void kextdProcessKernelResourceRequest(
78    CFDictionaryRef   request);
79kern_return_t kextdProcessUserLoadRequest(
80    CFDictionaryRef request,
81    uid_t           remote_euid,
82    pid_t           remote_pid);
83static OSReturn checkNonrootLoadAllowed(
84    OSKextRef kext,
85    uid_t     remote_euid,
86    pid_t     remote_pid);
87
88#pragma mark KextManager RPC routines & support
89/*******************************************************************************
90*******************************************************************************/
91kern_return_t _kextmanager_path_for_bundle_id(
92    mach_port_t       server,
93    kext_bundle_id_t  bundle_id,
94    posix_path_t      path,        // PATH_MAX
95    OSReturn        * kext_result)
96{
97    kern_return_t result    = kOSReturnSuccess;
98    CFStringRef   kextID    = NULL;  // must release
99    OSKextRef     theKext   = NULL;  // must release
100    CFURLRef      kextURL   = NULL;  // do not release
101    CFURLRef      absURL    = NULL;  // must release
102    char          crashInfo[sizeof(CRASH_INFO_USER_KEXT_PATH) +
103                  KMOD_MAX_NAME + PATH_MAX];
104
105    snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_USER_KEXT_PATH,
106        bundle_id);
107
108    setCrashLogMessage(crashInfo);
109
110    *kext_result = kOSReturnError;
111    path[0] = '\0';
112
113    OSKextLog(/* kext */ NULL,
114        kOSKextLogDebugLevel | kOSKextLogIPCFlag,
115        "Received client request for path to bundle %s.",
116        bundle_id);
117
118    kextID = CFStringCreateWithCString(kCFAllocatorDefault, bundle_id,
119        kCFStringEncodingUTF8);
120    if (!kextID) {
121        OSKextLogMemError();
122        *kext_result = kOSKextReturnNoMemory;
123        goto finish;
124    }
125
126    theKext = OSKextCreateWithIdentifier(kCFAllocatorDefault, kextID);
127    if (!theKext) {
128        OSKextLog(/* kext */ NULL,
129            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
130            "Kext %s not found for client path request.", bundle_id);
131        *kext_result = kOSKextReturnNotFound;
132        goto finish;
133    }
134    kextURL = OSKextGetURL(theKext);
135    if (!kextURL) {
136        OSKextLog(/* kext */ NULL,
137            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
138            "Kext %s found for client path request, but has no URL.", bundle_id);
139        goto finish;
140    }
141    absURL = CFURLCopyAbsoluteURL(kextURL);
142    if (!absURL) {
143        OSKextLogMemError();
144        *kext_result = kOSKextReturnNoMemory;
145        goto finish;
146    }
147    if (!CFURLGetFileSystemRepresentation(absURL, /* resolveToBase */ true,
148        (UInt8 *)path, PATH_MAX)) {
149
150        *kext_result = kOSKextReturnSerialization;
151        goto finish;
152    }
153
154    *kext_result = kOSReturnSuccess;
155
156    OSKextLog(/* kext */ NULL,
157        kOSKextLogDebugLevel | kOSKextLogIPCFlag,
158        "Returning path %s for identifier %s.", path, bundle_id);
159
160finish:
161    SAFE_RELEASE(kextID);
162    SAFE_RELEASE(theKext);
163    SAFE_RELEASE(absURL);
164
165    setCrashLogMessage(NULL);
166
167    return result;
168}
169
170#pragma mark Loginwindow RPC routines & support
171/*******************************************************************************
172* This function is executed in the main thread after its run loop gets
173* kicked by a client request.
174*******************************************************************************/
175kern_return_t _kextmanager_create_property_value_array(
176    mach_port_t  server,
177    char        * property_key,
178    char       ** xml_data_out,
179    int         * xml_data_length)
180
181{
182    kern_return_t result         = kOSReturnError;
183
184    CFStringRef   propertyKey    = NULL;  // must release
185    CFArrayRef    propertyValues = NULL;  // must release
186    char          crashInfo[sizeof(CRASH_INFO_USER_PROPERTY) +
187                  KMOD_MAX_NAME + PATH_MAX];
188
189    OSKextLog(/* kext */ NULL,
190        kOSKextLogProgressLevel | kOSKextLogGeneralFlag,
191        "Received client request for property value array.");
192
193    if (!xml_data_out || !xml_data_length) {
194        result = kOSKextReturnInvalidArgument;
195        goto finish;
196    }
197
198    *xml_data_length = 0;
199    *xml_data_out    = NULL;
200
201    snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_USER_PROPERTY,
202        property_key);
203
204    setCrashLogMessage(crashInfo);
205
206    propertyKey = CFStringCreateWithCString(kCFAllocatorDefault, property_key,
207        kCFStringEncodingUTF8);
208    if (!propertyKey) {
209        OSKextLogMemError();
210        goto finish;
211    }
212
213    if (readSystemKextPropertyValues(propertyKey, gKernelArchInfo,
214        /* forceUpdate? */ FALSE, &propertyValues)) {
215
216            result = sendPropertyValueResponse(propertyValues,
217                xml_data_out, xml_data_length);
218            goto finish;
219    }
220
221finish:
222    SAFE_RELEASE(propertyKey);
223    SAFE_RELEASE(propertyValues);
224
225    setCrashLogMessage(NULL);
226
227    OSKextFlushInfoDictionary(NULL /* all kexts */);
228    OSKextFlushLoadInfo(NULL /* all kexts */, /* flushDependencies */ true);
229
230    return result;
231}
232
233/*******************************************************************************
234*******************************************************************************/
235kern_return_t sendPropertyValueResponse(
236    CFArrayRef    propertyValues,
237    char       ** xml_data_out,
238    int         * xml_data_length)
239{
240    kern_return_t result    = kOSReturnError;
241    CFDataRef     plistData = NULL;  // must release
242    CFErrorRef    error     = NULL;  // must relase
243
244    plistData = CFPropertyListCreateData(kCFAllocatorDefault,
245         propertyValues, kCFPropertyListBinaryFormat_v1_0,
246         /* options */ 0,
247         &error);
248    if (!plistData) {
249        OSKextLog(/* kext */ NULL,
250            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
251            "Can't create plist data for property value response.");
252        log_CFError(/* kext */ NULL,
253            kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
254            error);
255        goto finish;
256    }
257
258    *xml_data_length = (int)CFDataGetLength(plistData);
259
260    if (*xml_data_length) {
261        result = vm_allocate(mach_task_self(), (vm_address_t *)xml_data_out,
262            *xml_data_length, VM_FLAGS_ANYWHERE);
263        if (result != kOSReturnSuccess) {
264            OSKextLog(/* kext */ NULL,
265                kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
266                "vm_allocate() failed.");
267            goto finish;
268        }
269        memcpy(*xml_data_out, CFDataGetBytePtr(plistData), *xml_data_length);
270    }
271
272finish:
273    SAFE_RELEASE(plistData);
274    SAFE_RELEASE(error);
275
276    return result;
277}
278
279#pragma mark Kernel Kext Requests
280
281#define KEXTD_LOCKED() (_gKextutilLock ? true:false)
282
283/*******************************************************************************
284* Incoming MIG message from kernel to let us know we should fetch requests from
285* it using kextd_process_kernel_requests().
286*******************************************************************************/
287kern_return_t svc_kextd_ping(mach_port_t mp __unused)
288{
289    bool shutdownRequested = false;
290
291    if (KEXTD_LOCKED()) {
292        gKernelRequestsPending = true;
293        return kOSReturnSuccess;
294    } else {
295        shutdownRequested = kextd_process_kernel_requests();
296        if (shutdownRequested) {
297            CFRunLoopStop(CFRunLoopGetCurrent());
298        }
299    }
300    return kOSReturnSuccess;
301}
302
303/*******************************************************************************
304*******************************************************************************/
305bool kextd_process_kernel_requests(void)
306{
307    CFArrayRef      kernelRequests             = NULL;  // must release
308    Boolean         loadNotificationReceived   = false;
309    Boolean         unloadNotificationReceived = false;
310    Boolean         prelinkedKernelRequested   = false;
311    Boolean         shutdownRequested          = false;
312    char          * scratchCString             = NULL;  // must free
313    CFIndex         count, i;
314
315   /* Stay in the while loop until _OSKextCopyKernelRequests() returns
316    * no more requests.
317    */
318    while (1) {
319        SAFE_RELEASE_NULL(kernelRequests);
320        kernelRequests = _OSKextCopyKernelRequests();
321        if (!kernelRequests || !CFArrayGetCount(kernelRequests)) {
322            break;
323        }
324
325        count = CFArrayGetCount(kernelRequests);
326        for (i = 0; i < count; i++) {
327            CFDictionaryRef request      = NULL; // do not release
328            CFStringRef     predicate    = NULL; // do not release
329
330            SAFE_FREE_NULL(scratchCString);
331
332            request = CFArrayGetValueAtIndex(kernelRequests, i);
333            predicate = request ? CFDictionaryGetValue(request,
334                CFSTR(kKextRequestPredicateKey)) : NULL;
335
336            if (!request) {
337                OSKextLog(/* kext */ NULL,
338                    kOSKextLogErrorLevel | kOSKextLogIPCFlag,
339                    "Empty kernel request.");
340                continue;
341            }
342            if (!predicate) {
343                OSKextLog(/* kext */ NULL,
344                    kOSKextLogErrorLevel | kOSKextLogIPCFlag,
345                    "No predicate in kernel request.");
346                continue;
347            }
348
349           /* Check the request predicate and process it or note it needs
350            * to be processed.
351            */
352            if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestPrelink))) {
353                OSKextLog(/* kext */ NULL,
354                    kOSKextLogProgressLevel | kOSKextLogIPCFlag,
355                    "Got prelink kernel request.");
356                prelinkedKernelRequested = true;
357            } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestKextdExit))) {
358                OSKextLog(/* kext */ NULL,
359                    kOSKextLogProgressLevel | kOSKextLogIPCFlag,
360                    "Got exit request from kernel.");
361                shutdownRequested = true;
362            } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestLoad))) {
363                OSKextLog(/* kext */ NULL,
364                    kOSKextLogProgressLevel | kOSKextLogIPCFlag,
365                    "Got load request from kernel.");
366                kextdProcessKernelLoadRequest(request);
367            } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateLoadNotification))) {
368               /* We don't do anything with the kext identifier because notify(3)
369                * doesn't allow for an argument.
370                */
371                loadNotificationReceived = true;
372            } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateUnloadNotification))) {
373               /* We don't do anything with the kext identifier because notify(3)
374                * doesn't allow for an argument.
375                */
376                unloadNotificationReceived = true;
377            } else if (CFEqual(predicate, CFSTR(kKextRequestPredicateRequestResource))) {
378                OSKextLog(/* kext */ NULL,
379                    kOSKextLogProgressLevel | kOSKextLogIPCFlag,
380                    "Got resource file request from kernel.");
381                kextdProcessKernelResourceRequest(request);
382            } else {
383                scratchCString = createUTF8CStringForCFString(predicate);
384                OSKextLog(/* kext */ NULL,
385                    kOSKextLogErrorLevel | kOSKextLogIPCFlag,
386                    "Unknown predicate%s%s in kernel request.",
387                    scratchCString ? " " : "",
388                    scratchCString ? scratchCString : "");
389            }
390        } /* for (i = 0; i < count; i++) */
391    } /* while (1) */
392
393// finish:
394
395    if (prelinkedKernelRequested) {
396        Boolean       readOnlyFS = FALSE;
397        struct statfs statfsBuffer;
398
399       /* If the statfs() fails we will forge ahead and try kextcache.
400        * Only if we know for sure it's read-only do we skip.
401        */
402        if (statfs("/System/Library/Caches", &statfsBuffer) == 0) {
403            if (statfsBuffer.f_flags & MNT_RDONLY) {
404                readOnlyFS = TRUE;
405
406                OSKextLog(/* kext */ NULL,
407                    kOSKextLogProgressLevel | kOSKextLogFileAccessFlag,
408                    "Skipping prelinked kernel build; read-only filesystem.");
409            }
410        }
411
412        if (!readOnlyFS) {
413            char * const kextcacheArgs[] = {
414                "/usr/sbin/kextcache",
415                "-F",
416                "-system-prelinked-kernel",
417                NULL };
418
419            OSKextLog(/* kext */ NULL,
420                kOSKextLogProgressLevel | kOSKextLogGeneralFlag,
421                "Building prelinked kernel.");
422
423            (void)fork_program("/usr/sbin/kextcache",
424                kextcacheArgs,
425                /* waitFlag */ false);
426        }
427    }
428
429    if (loadNotificationReceived) {
430        notify_post(kOSKextLoadNotification);
431    }
432    if (unloadNotificationReceived) {
433        notify_post(kOSKextUnloadNotification);
434    }
435
436    gKernelRequestsPending = false;
437
438    SAFE_FREE(scratchCString);
439    SAFE_RELEASE(kernelRequests);
440
441    OSKextFlushInfoDictionary(NULL /* all kexts */);
442    OSKextFlushLoadInfo(NULL /* all kexts */, /* flushDependencies */ true);
443
444    return shutdownRequested;
445}
446
447/*******************************************************************************
448* Kernel load request.
449*******************************************************************************/
450void
451kextdProcessKernelLoadRequest(CFDictionaryRef   request)
452{
453    CFDictionaryRef requestArgs     = NULL; // do not release
454    OSKextRef       osKext          = NULL; // do not release
455    OSReturn        osLoadResult    = kOSKextReturnNotFound;
456
457    CFArrayRef      loadList        = NULL;  // must release
458    CFStringRef     kextIdentifier  = NULL;  // do not release
459    char          * kext_id         = NULL;  // must free
460    char            crashInfo[sizeof(CRASH_INFO_KERNEL_KEXT_LOAD) + KMOD_MAX_NAME + PATH_MAX];
461
462    requestArgs = request ? CFDictionaryGetValue(request,
463        CFSTR(kKextRequestArgumentsKey)) : NULL;
464    kextIdentifier = requestArgs ? CFDictionaryGetValue(requestArgs,
465        CFSTR(kKextRequestArgumentBundleIdentifierKey)) : NULL;
466
467    if (!requestArgs) {
468        OSKextLog(/* kext */ NULL,
469            kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
470            "No arguments in kernel kext load request.");
471        goto finish;
472    }
473    if (!kextIdentifier) {
474        OSKextLog(/* kext */ NULL,
475            kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
476            "No kext ID in kernel kext load request.");
477        goto finish;
478    }
479    kext_id = createUTF8CStringForCFString(kextIdentifier);
480    if (!kext_id) {
481        // xxx - not much we can do here.
482        OSKextLogMemError();
483        goto finish;
484    }
485
486    snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_KERNEL_KEXT_LOAD,
487        kext_id);
488
489    setCrashLogMessage(crashInfo);
490
491   /* Read the extensions if necessary (also resets the release timer).
492    */
493    readExtensions();
494
495    OSKextLog(/* kext */ NULL,
496        kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
497        "Kernel requests kext with id %s.", kext_id);
498
499    osKext = OSKextGetKextWithIdentifier(kextIdentifier);
500    if (!osKext) {
501        OSKextLog(/* kext */ NULL,
502            kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
503            "Kext id %s not found; removing personalities from kernel.", kext_id);
504        OSKextRemovePersonalitiesForIdentifierFromKernel(kextIdentifier);
505        goto finish;
506    }
507
508   /* xxx - under what circumstances should we remove personalities?
509    * xxx - if the request gets into the kernel and fails, OSKext.cpp
510    * xxx - removes them, but there can be other failures on the way....
511    */
512    OSStatus  sigResult = checkKextSignature(osKext, true, false);
513    if ( sigResult != 0 ) {
514        if ( isInvalidSignatureAllowed() ) {
515            CFStringRef     myKextPath = NULL; // must release
516
517            myKextPath = copyKextPath(osKext);
518            OSKextLogCFString(NULL,
519                              kOSKextLogErrorLevel | kOSKextLogLoadFlag,
520                              CFSTR("kext-dev-mode allowing invalid signature %ld 0x%02lX for kext \"%@\""),
521                              (long)sigResult, (long)sigResult,
522                              myKextPath ? myKextPath : CFSTR("Unknown"));
523            SAFE_RELEASE(myKextPath);
524        }
525        else {
526            CFStringRef     myBundleID = NULL;         // do not release
527
528            myBundleID = OSKextGetIdentifier(osKext);
529            OSKextLogCFString(NULL,
530                              kOSKextLogErrorLevel |
531                              kOSKextLogLoadFlag | kOSKextLogIPCFlag,
532                              CFSTR("ERROR: invalid signature for %@, will not load"),
533                              myBundleID ? myBundleID : CFSTR("Unknown"));
534            OSKextRemoveKextPersonalitiesFromKernel(osKext);
535            goto finish;
536        }
537    }
538
539    osLoadResult = OSKextLoad(osKext);
540    if (osLoadResult != kOSReturnSuccess) {
541        OSKextLog(/* kext */ NULL,
542            kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
543            "Load %s failed; removing personalities from kernel.", kext_id);
544        OSKextRemoveKextPersonalitiesFromKernel(osKext);
545    } else {
546        if (kOSReturnSuccess != IOCatalogueModuleLoaded(
547            kIOMasterPortDefault, kext_id)) {
548
549            OSKextLog(/* kext */ NULL,
550                kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
551                "Failed to notify IOCatalogue that %s loaded.",
552                kext_id);
553        } else {
554            OSKextLog(/* kext */ NULL,
555                kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
556                "Loaded %s and notified IOCatalogue.",
557                kext_id);
558        }
559    }
560
561    if (osLoadResult == kOSKextReturnAuthentication) {
562        loadList = OSKextCopyLoadList(osKext, /* needAll? */ false);
563        recordNonsecureKexts(loadList);
564    }
565
566finish:
567    SAFE_RELEASE(loadList);
568    SAFE_FREE(kext_id);
569    setCrashLogMessage(NULL);
570
571    return;
572}
573
574/*******************************************************************************
575* Kernel resource file request.
576*******************************************************************************/
577#define kDSStoreFilename   ".DS_Store"
578
579void
580kextdProcessKernelResourceRequest(
581    CFDictionaryRef   request)
582{
583    CFDictionaryRef requestArgs            = NULL;  // do not release
584    OSKextRef       osKext                 = NULL;  // must release
585    CFDataRef       resource               = NULL;  // must release
586    OSReturn        requestResult          = kOSKextReturnInvalidArgument;
587
588    CFStringRef     kextIdentifier         = NULL;  // do not release
589    CFStringRef     resourceName           = NULL;  // do not release
590    CFURLRef        kextURL                = NULL;  // do not release
591    char          * kextIdentifierCString  = NULL;  // must free
592    char          * resourceNameCString    = NULL;  // must free
593    char            kextPathCString[PATH_MAX];
594    char            crashInfo[sizeof(CRASH_INFO_KERNEL_KEXT_RESOURCE) +
595                    KMOD_MAX_NAME + PATH_MAX];
596
597    requestArgs = request ? CFDictionaryGetValue(request,
598        CFSTR(kKextRequestArgumentsKey)) : NULL;
599    kextIdentifier = requestArgs ? CFDictionaryGetValue(requestArgs,
600        CFSTR(kKextRequestArgumentBundleIdentifierKey)) : NULL;
601    resourceName = requestArgs ? CFDictionaryGetValue(requestArgs,
602        CFSTR(kKextRequestArgumentNameKey)) : NULL;
603
604    OSKextLog(/* kext */ NULL,
605        kOSKextLogDebugLevel | kOSKextLogIPCFlag,
606        "Request for resource.");
607
608    if (!requestArgs) {
609        OSKextLog(/* kext */ NULL,
610            kOSKextLogProgressLevel | kOSKextLogIPCFlag,
611            "No arguments in kernel kext resource request.");
612        goto finish;
613    }
614    if (!kextIdentifier) {
615        OSKextLog(/* kext */ NULL,
616            kOSKextLogProgressLevel | kOSKextLogIPCFlag,
617            "No kext ID in kernel kext resource request.");
618        goto finish;
619    }
620    if (!resourceName) {
621        OSKextLog(/* kext */ NULL,
622            kOSKextLogProgressLevel | kOSKextLogIPCFlag,
623            "No resource name in kernel kext resource request.");
624        goto finish;
625    }
626
627    requestResult = kOSKextReturnNoMemory;
628
629    kextIdentifierCString = createUTF8CStringForCFString(kextIdentifier);
630    resourceNameCString = createUTF8CStringForCFString(resourceName);
631    if (!kextIdentifierCString || !resourceNameCString) {
632        // xxx - not much we can do here.
633        OSKextLogMemError();
634        goto finish;
635    }
636
637    snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_KERNEL_KEXT_RESOURCE,
638        resourceNameCString, kextIdentifierCString);
639
640    setCrashLogMessage(crashInfo);
641
642    if (CFEqual(resourceName, CFSTR(kDSStoreFilename))) {
643        requestResult = kOSKextReturnInvalidArgument;
644        OSKextLog(/* kext */ NULL,
645            kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogFileAccessFlag,
646            "Request for %s resource by %s - not allowed.",
647            kDSStoreFilename, kextIdentifierCString);
648        goto finish;
649    }
650
651   /* Read the extensions if necessary (also resets the release timer).
652    */
653    readExtensions();
654
655    OSKextLog(/* kext */ NULL,
656        kOSKextLogProgressLevel | kOSKextLogIPCFlag,
657        "Kernel requests resource %s from kext id %s.",
658        resourceNameCString, kextIdentifierCString);
659
660    requestResult = kOSKextReturnNotFound;
661
662    osKext = OSKextCreateWithIdentifier(kCFAllocatorDefault, kextIdentifier);
663    if (!osKext) {
664        OSKextLog(/* kext */ NULL,
665            kOSKextLogProgressLevel | kOSKextLogIPCFlag,
666            "Kext id %s not found; can't retrieve requested resource.",
667            kextIdentifierCString);
668        goto finish;
669    }
670
671    kextURL = OSKextGetURL(osKext);
672    if (!kextURL ||
673        !CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase? */ TRUE,
674            (UInt8 *)kextPathCString, sizeof(kextPathCString))) {
675
676            strlcpy(kextPathCString, "(unknown)", sizeof("(unknown)"));
677    }
678
679    OSKextLog(/* kext */ NULL,
680        kOSKextLogProgressLevel | kOSKextLogIPCFlag,
681        "Seeking resource %s in %s.",
682        resourceNameCString, kextPathCString);
683
684    if (!OSKextIsValid(osKext)) {
685        OSKextLog(/* kext */ NULL,
686            kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogValidationFlag,
687            "%s is not valid; can't retrieve requested resource.",
688            kextPathCString);
689        requestResult = kOSKextReturnValidation;
690        goto finish;
691    }
692
693
694    if (!OSKextIsAuthentic(osKext)) {
695        OSKextLog(/* kext */ NULL,
696            kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogAuthenticationFlag,
697            "%s has incorrect permissions; can't retrieve requested resource.",
698            kextPathCString);
699        requestResult = kOSKextReturnAuthentication;
700        goto finish;
701    }
702
703    resource = OSKextCopyResource(osKext, resourceName,
704        /* resourceType */ NULL);
705    if (!resource) {
706        OSKextLog(/* kext */ NULL,
707            kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogFileAccessFlag,
708            "Can't find resource %s in %s.",
709            resourceNameCString, kextPathCString);
710        requestResult = kOSKextReturnNotFound;
711        goto finish;
712    }
713
714    requestResult = kOSReturnSuccess;
715
716    OSKextLog(/* kext */ NULL,
717        kOSKextLogProgressLevel | kOSKextLogIPCFlag | kOSKextLogValidationFlag,
718        "Found resource %s in %s; sending to kernel.",
719        resourceNameCString, kextPathCString);
720
721finish:
722    // now we send it to the kernel
723    (void) _OSKextSendResource(request, requestResult, resource);
724
725    SAFE_RELEASE(resource);
726    SAFE_RELEASE(osKext);
727    SAFE_FREE(kextIdentifierCString);
728    SAFE_FREE(resourceNameCString);
729    setCrashLogMessage(NULL);
730    return;
731}
732
733#pragma mark User Space Kext Load Requests
734/*******************************************************************************
735* User space load request.
736*******************************************************************************/
737kern_return_t
738_kextmanager_load_kext(
739    mach_port_t   server,
740    audit_token_t audit_token,
741    char        * xml_data_in,
742    int           xml_data_length)
743{
744    OSReturn        result      = kOSReturnError;
745    CFDataRef       requestData = NULL;  // must release
746    CFDictionaryRef request     = NULL;  // must release
747    CFErrorRef      error       = NULL;  // must release
748    pid_t           remote_pid  = -1;
749    uid_t           remote_euid = -1;
750
751    requestData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
752        (const UInt8 *)xml_data_in, xml_data_length,
753        /* deallocator */ kCFAllocatorNull);
754    if (!requestData) {
755        OSKextLogMemError();
756        result = kOSKextReturnNoMemory;
757        goto finish;
758    }
759    request = CFPropertyListCreateWithData(kCFAllocatorDefault,
760        requestData, /* options */ 0, /* format */ NULL,
761        &error);
762    if (!request) {
763        OSKextLog(/* kext */ NULL,
764            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
765            "Can't read kext load request.");
766        log_CFError(/* kext */ NULL,
767            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
768            error);
769        result = kOSKextReturnSerialization;
770        goto finish;
771    }
772    if (CFGetTypeID(request) != CFDictionaryGetTypeID()) {
773        result = kOSKextReturnBadData;
774        goto finish;
775    }
776
777    audit_token_to_au32(audit_token, /* audit UID */ NULL,
778            &remote_euid, /* egid */ NULL, /* ruid */ NULL, /* rgid */ NULL,
779            &remote_pid, /* asid */ NULL, /* au_tid_t */ NULL);
780
781    result = kextdProcessUserLoadRequest(request, remote_euid, remote_pid);
782
783finish:
784    SAFE_RELEASE(requestData);
785    SAFE_RELEASE(request);
786    SAFE_RELEASE(error);
787
788    OSKextFlushInfoDictionary(NULL /* all kexts */);
789    OSKextFlushLoadInfo(NULL /* all kexts */, /* flushDependencies */ true);
790
791   /* MIG is consume-on-success
792    * xxx - do we need separate result & op-result?
793    */
794    if (result == kOSReturnSuccess) {
795        vm_deallocate(mach_task_self(), (vm_address_t)xml_data_in,
796            (vm_size_t)xml_data_length);
797    }
798    return result;
799}
800
801/*******************************************************************************
802*******************************************************************************/
803const char * nameForPID(pid_t pid)
804{
805    char * result      = NULL;
806    int    path_length = 0;
807    char   path[PROC_PIDPATHINFO_MAXSIZE];
808
809    path_length = proc_pidpath(pid, path,
810        sizeof(path));
811    if (path_length > 0) {
812        result = basename(path);
813    }
814    if (!result) {
815        result = "(unknown)";
816    }
817    return result;
818}
819
820/*******************************************************************************
821*******************************************************************************/
822#define UNKNOWN_KEXT  "unknown kext"
823#define SYSTEM_FOLDER "/System/"
824
825#define _kSystemExtensionsDirSlash   (kSystemExtensionsDir "/")
826#define _kLibraryExtensionsDirSlash   (kLibraryExtensionsDir "/")
827#define _kSystemFilesystemsDirSlash  ("/System/Library/Filesystems/")
828
829/*******************************************************************************
830*******************************************************************************/
831static CFURLRef createAbsOrRealURLForURL(
832    CFURLRef   anURL,
833    uid_t      remote_euid,
834    pid_t      remote_pid,
835    OSReturn * error)
836{
837    CFURLRef result      = NULL;
838    OSReturn localError  = kOSReturnSuccess;
839    Boolean  inLE        = FALSE;
840    Boolean  inSLE       = FALSE;
841    Boolean  inSLF       = FALSE;
842    char     urlPathCString[PATH_MAX];
843    char     realpathCString[PATH_MAX];
844
845    if (!CFURLGetFileSystemRepresentation(anURL, /* resolveToBase? */ TRUE,
846        (UInt8 *)urlPathCString, sizeof(urlPathCString)))
847    {
848        OSKextLog(/* kext */ NULL,
849            kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
850            "Can't get path from URL for kext load request.");
851        localError = kOSKextReturnSerialization;
852        goto finish;
853    }
854
855    if (remote_euid == 0) {
856        result = CFURLCopyAbsoluteURL(anURL);
857        if (!result) {
858            OSKextLogMemError();
859            goto finish;
860        }
861        goto finish;
862    } else {
863
864        inSLE = (0 == strncmp(urlPathCString, _kSystemExtensionsDirSlash,
865                              strlen(_kSystemExtensionsDirSlash)));
866        inLE = (0 == strncmp(urlPathCString, _kLibraryExtensionsDirSlash,
867                             strlen(_kLibraryExtensionsDirSlash)));
868        inSLF = (0 == strncmp(urlPathCString, _kSystemFilesystemsDirSlash,
869                              strlen(_kSystemFilesystemsDirSlash)));
870
871       /*****
872        * May want to open these checks to use OSKextGetSystemExtensionsFolderURLs().
873        * For now, keep it tight and just do /System/Library/Extensions & Filesystems.
874        */
875        if (!inSLE && !inSLF && !inLE) {
876            localError = kOSKextReturnNotPrivileged;
877            if (!inSLE && !inSLF) {
878                OSKextLog(/* kext */ NULL,
879                    kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
880                    "Request from non-root process '%s' (euid %d) to load %s - "
881                          "not in extensions dirs or filesystems folder.",
882                    nameForPID(remote_pid), remote_euid, urlPathCString);
883            }
884            goto finish;
885        }
886
887        if (!realpath(urlPathCString, realpathCString)) {
888
889            localError = kOSReturnError; // xxx - should we have a filesystem error?
890            OSKextLog(/* kext */ NULL,
891                kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
892                "Unable to resolve raw path %s.", urlPathCString);
893            goto finish;
894        }
895
896       /*****
897        * Check the path once more now that we've resolved it with realpath().
898        */
899        inSLE = (0 == strncmp(realpathCString, _kSystemExtensionsDirSlash,
900                              strlen(_kSystemExtensionsDirSlash)));
901        inLE = (0 == strncmp(urlPathCString, _kLibraryExtensionsDirSlash,
902                             strlen(_kLibraryExtensionsDirSlash)));
903        inSLF = (0 == strncmp(realpathCString, _kSystemFilesystemsDirSlash,
904                              strlen(_kSystemFilesystemsDirSlash)));
905
906        if (!inSLE && !inSLF && !inLE) {
907
908            localError = kOSKextReturnNotPrivileged;
909            OSKextLog(/* kext */ NULL,
910                kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
911                "Request from non-root process '%s' (euid %d) to load %s - "
912                "(real path %s) - not in extensions dirs or filesystems folder.",
913                nameForPID(remote_pid), remote_euid, urlPathCString,
914                realpathCString);
915            goto finish;
916        }
917    }
918
919    result = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
920        (UInt8 *)realpathCString, strlen(realpathCString), /* isDir */ TRUE);
921    if (!result) {
922        OSKextLogMemError();
923        goto finish;
924    }
925
926finish:
927    if (error) {
928        *error = localError;
929    }
930    return result;
931}
932
933/*******************************************************************************
934*******************************************************************************/
935static OSReturn
936checkNonrootLoadAllowed(
937    OSKextRef kext,
938    uid_t     remote_euid,
939    pid_t     remote_pid)
940{
941    OSReturn    result       = kOSKextReturnNotPrivileged;
942    CFArrayRef  loadList     = NULL;  // must release
943    CFStringRef kextPath     = NULL;  // must release
944    Boolean     kextAllows   = TRUE;
945    char        kextPathCString[PATH_MAX];
946    CFIndex     count, index;
947
948    loadList = OSKextCopyLoadList(kext, /* needAll?*/ TRUE);
949    if (!loadList) {
950        OSKextLog(/* kext */ NULL,
951            kOSKextLogErrorLevel | kOSKextLogLoadFlag |
952            kOSKextLogDependenciesFlag | kOSKextLogIPCFlag,
953            "Can't resolve dependencies for kext load request.");
954        result = kOSKextReturnDependencies;
955        goto finish;
956    }
957
958    count = CFArrayGetCount(loadList);
959    for (index = count - 1; index >= 0; index--) {
960        OSKextRef thisKext = (OSKextRef)CFArrayGetValueAtIndex(loadList, index);
961        CFBooleanRef allowed = (CFBooleanRef)OSKextGetValueForInfoDictionaryKey(
962            thisKext, CFSTR(kOSBundleAllowUserLoadKey));
963        CFURLRef  kextURL = OSKextGetURL(thisKext);
964
965        SAFE_RELEASE_NULL(kextPath);
966
967        kextPath = CFURLCopyFileSystemPath(kextURL, kCFURLPOSIXPathStyle);
968        if (!kextPath) {
969            OSKextLogMemError();
970            result = kOSKextReturnNoMemory;
971        }
972        if (!CFURLGetFileSystemRepresentation(kextURL, /* resolveToBase? */ TRUE,
973            (UInt8 *)kextPathCString, sizeof(kextPathCString))) {
974            strlcpy(kextPathCString, UNKNOWN_KEXT, sizeof(UNKNOWN_KEXT));
975            OSKextLog(/* kext */ NULL,
976                kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
977                "Can't get path from URL for kext load request.");
978            result = kOSKextReturnSerialization;
979            goto finish;
980        }
981
982        if (!allowed ||
983            (CFGetTypeID(allowed) != CFBooleanGetTypeID()) ||
984            !CFBooleanGetValue(allowed)) {
985
986            kextAllows = FALSE;
987            goto finish;
988        }
989    }
990
991    result = kOSReturnSuccess;
992
993finish:
994    SAFE_RELEASE(loadList);
995    SAFE_RELEASE(kextPath);
996
997    if (!kextAllows) {
998        result = kOSKextReturnNotPrivileged;
999
1000        OSKextLog(/* kext */ NULL,
1001            kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
1002            "Request from non-root process '%s' (euid %d) to load %s - not allowed.",
1003            nameForPID(remote_pid), remote_euid, kextPathCString);
1004    }
1005
1006    return result;
1007}
1008
1009/*******************************************************************************
1010*******************************************************************************/
1011kern_return_t
1012kextdProcessUserLoadRequest(
1013    CFDictionaryRef request,
1014    uid_t           remote_euid,
1015    pid_t           remote_pid)
1016{
1017    OSReturn          result                   = kOSReturnSuccess;
1018    CFStringRef       kextID                   = NULL;  // do not release
1019    char *            kextIDString             = NULL;  // must free
1020    CFStringRef       kextPath                 = NULL;  // do not release
1021    CFArrayRef        dependencyPaths          = NULL;  // do not release
1022    CFURLRef          kextURL                  = NULL;  // must release
1023    CFURLRef          kextAbsURL               = NULL;  // must release
1024    OSKextRef         theKext                  = NULL;  // must release
1025    CFArrayRef        kexts                    = NULL;  // must release
1026    CFMutableArrayRef dependencyURLs           = NULL;  // must release
1027    CFURLRef          dependencyURL            = NULL;  // must release
1028    CFURLRef          dependencyAbsURL         = NULL;  // must release
1029    CFArrayRef        dependencyKexts          = NULL;  // must release
1030    CFArrayRef        loadList                 = NULL;  // must release
1031
1032    char              kextPathString[PATH_MAX] = "unknown";
1033    char              crashInfo[sizeof(CRASH_INFO_USER_KEXT_LOAD) +
1034                      KMOD_MAX_NAME + PATH_MAX];
1035    CFIndex           count, index;
1036
1037   /* First get the identifier or URL to load, and convert it to a C string
1038    * for logging.
1039    */
1040    kextID = (CFStringRef)CFDictionaryGetValue(request, kKextLoadIdentifierKey);
1041    if (kextID) {
1042        if (CFGetTypeID(kextID) != CFStringGetTypeID()) {
1043            result = kOSKextReturnInvalidArgument;
1044            goto finish;
1045        }
1046        kextIDString = createUTF8CStringForCFString(kextID);
1047        if (!kextIDString) {
1048            OSKextLogMemError();
1049            goto finish;
1050        }
1051    } else {
1052        kextPath = (CFStringRef)CFDictionaryGetValue(request, kKextLoadPathKey);
1053        if (!kextPath || CFGetTypeID(kextPath) != CFStringGetTypeID()) {
1054            result = kOSKextReturnInvalidArgument;
1055            goto finish;
1056        }
1057
1058        if (!CFStringHasPrefix(kextPath, CFSTR("/"))) {
1059            OSKextLog(/* kext */ NULL,
1060                kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
1061                "Error: Request from '%s' (euid %d) to load kext with relative path.",
1062                nameForPID(remote_pid), remote_euid);
1063            result = kOSKextReturnInvalidArgument;
1064            goto finish;
1065        }
1066
1067        kextURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
1068            kextPath, kCFURLPOSIXPathStyle, /* isDir? */ true);
1069        if (!kextURL) {
1070            result = kOSKextReturnSerialization;  // xxx - or other?
1071            goto finish;
1072        }
1073        result = kOSReturnError;
1074        kextAbsURL = createAbsOrRealURLForURL(kextURL,
1075            remote_euid, remote_pid, &result);
1076        if (!kextAbsURL) {
1077            goto finish;
1078        }
1079        CFURLGetFileSystemRepresentation(kextAbsURL, /* resolveToBase */ true,
1080                                         (UInt8 *)kextPathString,
1081                                         sizeof(kextPathString));
1082    }
1083
1084   /* Read the extensions if necessary (also resets the release timer).
1085    */
1086    readExtensions();
1087
1088   /* Now log before the attempt, then try to look up or create the kext.
1089    */
1090    if (remote_euid != 0) {
1091        OSKextLog(/* kext */ NULL,
1092            kOSKextLogProgressLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
1093                "Request from '%s' (euid %d) to load %s.",
1094                  nameForPID(remote_pid), remote_euid,
1095                  kextIDString ? kextIDString : kextPathString);
1096    }
1097
1098   /* Open any dependencies provided, *before* we create the kext, since
1099    * a request by identifier must be resolvable from the dependencies
1100    * as well as system extensions folders.
1101    */
1102    dependencyPaths = (CFArrayRef)CFDictionaryGetValue(request,
1103        kKextLoadDependenciesKey);
1104    if (dependencyPaths) {
1105        if (CFGetTypeID(dependencyPaths) != CFArrayGetTypeID()) {
1106            result = kOSKextReturnInvalidArgument;
1107            goto finish;
1108        }
1109
1110        count = CFArrayGetCount(dependencyPaths);
1111
1112        dependencyURLs = CFArrayCreateMutable(kCFAllocatorDefault,
1113            /* capacity */ count,
1114            &kCFTypeArrayCallBacks);
1115        if (!dependencyURLs) {
1116            result = kOSKextReturnNoMemory;
1117            goto finish;
1118        }
1119
1120        for (index = 0; index < count; index++) {
1121            CFStringRef thisPath = (CFStringRef)CFArrayGetValueAtIndex(
1122                dependencyPaths, index);
1123
1124            SAFE_RELEASE_NULL(dependencyURL);
1125            SAFE_RELEASE_NULL(dependencyAbsURL);
1126            if (CFGetTypeID(thisPath) != CFStringGetTypeID()) {
1127                result = kOSKextReturnInvalidArgument;
1128                goto finish;
1129            }
1130            if (!CFStringHasPrefix(thisPath, CFSTR("/"))) {
1131                OSKextLog(/* kext */ NULL,
1132                    kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
1133                    "Error: Request to load kext using dependency with relative path.");
1134                result = kOSKextReturnInvalidArgument;
1135                goto finish;
1136            }
1137
1138            dependencyURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
1139                thisPath, kCFURLPOSIXPathStyle, /* isDir? */ true);
1140            if (!dependencyURL) {
1141                result = kOSKextReturnSerialization;  // xxx - or other?
1142                goto finish;
1143            }
1144            result = kOSReturnError;
1145            dependencyAbsURL = createAbsOrRealURLForURL(dependencyURL,
1146                remote_euid, remote_pid, &result);
1147            if (!dependencyAbsURL) {
1148                goto finish;
1149            }
1150            CFArrayAppendValue(dependencyURLs, dependencyAbsURL);
1151        }
1152        dependencyKexts = OSKextCreateKextsFromURLs(kCFAllocatorDefault,
1153            dependencyURLs);
1154        if (!dependencyKexts) {
1155            result = kOSReturnError;
1156            goto finish;
1157        }
1158    }
1159
1160    snprintf(crashInfo, sizeof(crashInfo), CRASH_INFO_USER_KEXT_LOAD,
1161            kextIDString ? kextIDString : kextPathString);
1162
1163    setCrashLogMessage(crashInfo);
1164
1165
1166    if (kextID) {
1167        theKext = OSKextGetKextWithIdentifier(kextID);
1168        if (theKext) {
1169            CFRetain(theKext);  // we're going to release it
1170        }
1171    } else {
1172       /* Make sure we also read the plugins of the kext we're asked to load,
1173        * but only if we manage to open the kext itself (or we'll get too many
1174        * error messages).
1175        */
1176        theKext = OSKextCreate(kCFAllocatorDefault, kextAbsURL);
1177        if (theKext) {
1178            kexts = OSKextCreateKextsFromURL(kCFAllocatorDefault, kextAbsURL);
1179            kextIDString = createUTF8CStringForCFString(OSKextGetIdentifier(theKext));
1180            if (!kextIDString) {
1181                OSKextLogMemError();
1182                goto finish;
1183            }
1184        }
1185    }
1186
1187    if (!theKext) {
1188        OSKextLog(/* kext */ NULL,
1189            kOSKextLogErrorLevel | kOSKextLogLoadFlag | kOSKextLogIPCFlag,
1190            "Error: Kext %s - not found/unable to create.",
1191            kextIDString ? kextIDString : kextPathString);
1192        result = kOSKextReturnNotFound;
1193        goto finish;
1194    }
1195
1196    if (remote_euid != 0) {
1197        result = checkNonrootLoadAllowed(theKext, remote_euid, remote_pid);
1198        if (result != kOSReturnSuccess) {
1199            goto finish;
1200        }
1201    }
1202
1203    /* Get dictionary of all our excluded kexts */
1204    if (OSKextIsInExcludeList(theKext, false)) {
1205        CFMutableDictionaryRef myAlertInfoDict = NULL; // must release
1206        addKextToAlertDict(&myAlertInfoDict, theKext);
1207        if (myAlertInfoDict) {
1208            CFRetain(myAlertInfoDict); // writeKextAlertPlist will release
1209            dispatch_async(dispatch_get_main_queue(), ^ {
1210                writeKextAlertPlist(myAlertInfoDict, EXCLUDED_KEXT_ALERT);
1211            });
1212            SAFE_RELEASE(myAlertInfoDict);
1213        }
1214
1215        messageTraceExcludedKext(theKext);
1216        OSKextLog(NULL,
1217                  kOSKextLogErrorLevel | kOSKextLogArchiveFlag |
1218                  kOSKextLogValidationFlag | kOSKextLogGeneralFlag,
1219                  "%s is in exclude list; omitting.",
1220                  kextIDString ? kextIDString : kextPathString);
1221        result = kOSKextReturnNotLoadable;
1222        goto finish;
1223    }
1224
1225    if (__esp_enabled()) {
1226        xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
1227        if (dict == NULL) {
1228            result = kOSKextReturnNotLoadable;
1229            goto finish;
1230        }
1231        xpc_dictionary_set_int64(dict, "euid", remote_euid);
1232        xpc_dictionary_set_int64(dict, "pid", remote_pid);
1233        if (kextIDString != NULL) {
1234            xpc_dictionary_set_string(dict, "kextID", kextIDString);
1235        }
1236        if (kextPathString != NULL) {
1237            xpc_dictionary_set_string(dict, "kextPath", kextPathString);
1238        }
1239        int esp_result = __esp_check("kext-load", dict);
1240        xpc_release(dict);
1241        if (esp_result != 0) {
1242            result = kOSKextReturnNotLoadable;
1243            goto finish;
1244        }
1245    }
1246
1247    /* consult sandboxing system to make sure this is OK
1248     * <rdar://problem/11015459
1249     */
1250    if (sandbox_check(remote_pid, "system-kext-load",
1251                      SANDBOX_FILTER_KEXT_BUNDLE_ID,
1252                      kextIDString) != 0 )  {
1253        OSKextLog(NULL,
1254                  kOSKextLogErrorLevel | kOSKextLogArchiveFlag |
1255                  kOSKextLogValidationFlag | kOSKextLogGeneralFlag,
1256                  "%s failed sandbox check; omitting.", kextIDString);
1257        result = kOSKextReturnNotLoadable;
1258        goto finish;
1259    }
1260
1261    OSStatus    sigResult = checkKextSignature(theKext, true, false);
1262    if ( sigResult != 0 ) {
1263        if ( isInvalidSignatureAllowed() ) {
1264            CFStringRef     myKextPath = NULL; // must release
1265            myKextPath = copyKextPath(theKext);
1266            OSKextLogCFString(NULL,
1267                              kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1268                              CFSTR("kext-dev-mode allowing invalid signature %ld 0x%02lX for kext \"%@\""),
1269                              (long)sigResult, (long)sigResult,
1270                              myKextPath ? myKextPath : CFSTR("Unknown"));
1271            SAFE_RELEASE(myKextPath);
1272        }
1273        else {
1274            CFStringRef         myBundleID;          // do not release
1275
1276            myBundleID = OSKextGetIdentifier(theKext);
1277            OSKextLogCFString(NULL,
1278                              kOSKextLogErrorLevel |
1279                              kOSKextLogLoadFlag | kOSKextLogIPCFlag,
1280                              CFSTR("ERROR: invalid signature for %@, will not load"),
1281                              myBundleID ? myBundleID : CFSTR("Unknown"));
1282            result = kOSKextReturnNotLoadable;
1283            goto finish;
1284        }
1285    }
1286
1287   /* The codepath from this function will do any error logging
1288    * and cleanup needed.
1289    */
1290    result = OSKextLoadWithOptions(theKext,
1291        /* statExclusion */ kOSKextExcludeNone,
1292        /* addPersonalitiesExclusion */ kOSKextExcludeNone,
1293        /* personalityNames */ NULL,
1294        /* delayAutounloadFlag */ false);
1295
1296finish:
1297    SAFE_RELEASE(kextURL);
1298    SAFE_RELEASE(kextAbsURL);
1299    SAFE_RELEASE(kexts);
1300    SAFE_RELEASE(theKext);
1301    SAFE_RELEASE(dependencyURLs);
1302    SAFE_RELEASE(dependencyURL);
1303    SAFE_RELEASE(dependencyAbsURL);
1304    SAFE_RELEASE(dependencyKexts);
1305    SAFE_RELEASE(loadList);
1306    SAFE_FREE(kextIDString);
1307
1308    setCrashLogMessage(NULL);
1309
1310    return result;
1311}
1312