1/*
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28#include <IOKit/IOKitLib.h>
29#include <IOKit/IOKitServer.h>
30#include <IOKit/kext/OSKextPrivate.h>
31#include <IOKit/IOCFSerialize.h>
32
33#include <sys/stat.h>
34#include <sys/mman.h>
35#include <libc.h>
36#include <zlib.h>
37
38#include "kextd_main.h"
39#include "kextd_personalities.h"
40#include "kextd_usernotification.h"
41#include "kextd_globals.h"
42
43static OSReturn sendCachedPersonalitiesToKernel(Boolean resetFlag);
44
45/*******************************************************************************
46*******************************************************************************/
47OSReturn sendSystemKextPersonalitiesToKernel(
48    CFArrayRef kexts,
49    Boolean    resetFlag)
50{
51    OSReturn          result         = kOSReturnSuccess;  // optimistic
52    CFArrayRef        personalities  = NULL;  // must release
53    CFMutableArrayRef authenticKexts = NULL; // must release
54    CFIndex           count, i;
55
56   /* Note that we are going to finish on success here!
57    * If we sent personalities we are done.
58    * sendCachedPersonalitiesToKernel() logs a msg on failure.
59    */
60    result = sendCachedPersonalitiesToKernel(resetFlag);
61    if (result == kOSReturnSuccess) {
62        goto finish;
63    }
64
65   /* If we didn't send from cache, send from the kexts. This will cause
66    * lots of I/O.
67    */
68    if (!createCFMutableArray(&authenticKexts, &kCFTypeArrayCallBacks)) {
69        OSKextLogMemError();
70        goto finish;
71    }
72
73   /* Check all the kexts to see if we need to raise alerts
74    * about improperly-installed extensions.
75    */
76    recordNonsecureKexts(kexts);
77
78    count = CFArrayGetCount(kexts);
79    for (i = 0; i < count; i++) {
80        OSKextRef aKext = (OSKextRef)CFArrayGetValueAtIndex(kexts, i);
81        if (OSKextIsAuthentic(aKext)) {
82            CFArrayAppendValue(authenticKexts, aKext);
83        }
84    }
85
86    result = OSKextSendPersonalitiesOfKextsToKernel(authenticKexts,
87        resetFlag);
88    if (result != kOSReturnSuccess) {
89        goto finish;
90    }
91
92    personalities = OSKextCopyPersonalitiesOfKexts(authenticKexts);
93
94   /* Now try to write the cache file. Don't save the return value
95    * of that function, we're more concerned with whether personalities
96    * have actually gone to the kernel.
97    */
98    _OSKextWriteCache(OSKextGetSystemExtensionsFolderURLs(),
99            CFSTR(kIOKitPersonalitiesKey), gKernelArchInfo,
100            _kOSKextCacheFormatIOXML, personalities);
101
102finish:
103    if (result != kOSReturnSuccess) {
104        OSKextLog(/* kext */ NULL,
105            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
106           "Error: Couldn't send kext personalities to the IOCatalogue.");
107    } else if (personalities) {
108        OSKextLog(/* kext */ NULL,
109            kOSKextLogProgressLevel | kOSKextLogIPCFlag |
110            kOSKextLogKextBookkeepingFlag,
111            "Sent %ld kext personalities to the IOCatalogue.",
112            CFArrayGetCount(personalities));
113    }
114    SAFE_RELEASE(personalities);
115    SAFE_RELEASE(authenticKexts);
116    return result;
117}
118
119/*******************************************************************************
120*******************************************************************************/
121static OSReturn sendCachedPersonalitiesToKernel(Boolean resetFlag)
122{
123    OSReturn  result    = kOSReturnError;
124    CFDataRef cacheData = NULL;  // must release
125
126    if (!_OSKextReadCache(gRepositoryURLs, CFSTR(kIOKitPersonalitiesKey),
127        gKernelArchInfo, _kOSKextCacheFormatIOXML,
128        /* parseXML? */ false, (CFPropertyListRef *)&cacheData)) {
129
130        goto finish;
131    }
132
133    OSKextLogCFString(/* kext */ NULL,
134        kOSKextLogProgressLevel | kOSKextLogIPCFlag |
135        kOSKextLogKextBookkeepingFlag,
136        CFSTR("%@"), CFSTR("Sending cached kext personalities to IOCatalogue."));
137
138    result = IOCatalogueSendData(kIOMasterPortDefault,
139        resetFlag ? kIOCatalogResetDrivers : kIOCatalogAddDrivers,
140        (char *)CFDataGetBytePtr(cacheData), (unsigned int)CFDataGetLength(cacheData));
141    if (result != kOSReturnSuccess) {
142        OSKextLog(/* kext */ NULL,
143            kOSKextLogErrorLevel | kOSKextLogIPCFlag,
144           "error: couldn't send personalities to the kernel.");
145        goto finish;
146    }
147
148    OSKextLogCFString(/* kext */ NULL,
149        kOSKextLogProgressLevel | kOSKextLogIPCFlag |
150        kOSKextLogKextBookkeepingFlag,
151        CFSTR("%@"), CFSTR("Sent cached kext personalities to the IOCatalogue."));
152
153    result = kOSReturnSuccess;
154
155finish:
156    SAFE_RELEASE(cacheData);
157    return result;
158}
159
160