1/*
2 * Copyright (c) 2000-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 <mach/mach.h>
29#include <TargetConditionals.h>
30#include <mach/kmod.h>
31#include <sys/param.h>
32#include <mach/mach_error.h>
33#include <servers/bootstrap.h>
34#include <bootstrap_priv.h>
35#include <syslog.h>
36#include <stdarg.h>
37
38#include "OSKext.h"
39#include "misc_util.h"
40#include "KextManager.h"
41#include "KextManagerPriv.h"
42#include "kextmanager_mig.h"
43
44/*********************************************************************
45* IMPORTANT: All calls in this module should be simple RPCs to kextd
46* or use the OSKext library *without* creating any OSKext objects.
47*********************************************************************/
48
49static kern_return_t get_kextd_port(mach_port_t *kextd_port); // internal convenience function
50
51/*********************************************************************
52*********************************************************************/
53CFURLRef KextManagerCreateURLForBundleIdentifier(
54    CFAllocatorRef allocator,
55    CFStringRef    bundleIdentifier)
56{
57    CFURLRef bundleURL = NULL;  // returned
58
59    kern_return_t kern_result = kOSReturnError;
60    char bundle_id[KMOD_MAX_NAME] = "";
61
62    mach_port_t   kextd_port = MACH_PORT_NULL;
63
64    char bundle_path[MAXPATHLEN] = "";
65    CFStringRef bundlePath = NULL;  // must free
66    OSReturn kext_result = kOSReturnError;
67    kext_result_t tmpRes;
68
69    if (!bundleIdentifier) {
70        goto finish;
71    }
72
73    if (!CFStringGetCString(bundleIdentifier,
74        bundle_id, sizeof(bundle_id) - 1, kCFStringEncodingUTF8)) {
75        goto finish;
76    }
77
78    kern_result = get_kextd_port(&kextd_port);
79    if (kern_result != kOSReturnSuccess) {
80        goto finish;
81    }
82
83    kern_result = kextmanager_path_for_bundle_id(
84        kextd_port, bundle_id, bundle_path, &tmpRes);
85    kext_result = tmpRes;
86    if (kern_result != kOSReturnSuccess) {
87        goto finish;
88    }
89
90    if (kext_result != kOSReturnSuccess) {
91        goto finish;
92    }
93
94    bundlePath = CFStringCreateWithCString(kCFAllocatorDefault,
95        bundle_path, kCFStringEncodingUTF8);
96    if (!bundlePath) {
97        goto finish;
98    }
99
100    bundleURL = CFURLCreateWithFileSystemPath(allocator,
101        bundlePath, kCFURLPOSIXPathStyle, true);
102
103finish:
104
105    if (bundlePath)  CFRelease(bundlePath);
106
107    return bundleURL;
108}
109
110/*********************************************************************
111* Internal function for use by KextManagerLoadKextWithIdentifier()
112* and KextManagerLoadKextWithURL().
113*********************************************************************/
114OSReturn __KextManagerSendLoadKextRequest(
115    CFMutableDictionaryRef  requestDict,
116    CFArrayRef              dependencyKextAndFolderURLs)
117{
118    OSReturn           result           = kOSReturnError;
119    mach_port_t        kextd_port       = MACH_PORT_NULL;
120    CFDataRef          requestData      = NULL;  // must release
121    CFMutableArrayRef  dependencyPaths  = NULL;  // must release
122    CFURLRef           dependencyAbsURL = NULL;  // must release
123    CFStringRef        dependencyPath   = NULL;  // must release
124    CFErrorRef         error            = NULL;  // must release
125
126    if (!requestDict) {
127        result = kOSKextReturnInvalidArgument;
128        goto finish;
129    }
130
131    result = get_kextd_port(&kextd_port);
132    if (result != kOSReturnSuccess) {
133        goto finish;
134    }
135
136    if (dependencyKextAndFolderURLs &&
137        CFArrayGetCount(dependencyKextAndFolderURLs)) {
138
139        CFIndex count, index;
140
141        dependencyPaths = CFArrayCreateMutable(kCFAllocatorDefault,
142            /* capacity */ 0, &kCFTypeArrayCallBacks);
143        if (!dependencyPaths) {
144            result = kOSKextReturnNoMemory;
145            goto finish;
146        }
147        CFDictionarySetValue(requestDict, kKextLoadDependenciesKey,
148            dependencyPaths);
149
150        count = CFArrayGetCount(dependencyKextAndFolderURLs);
151        for (index = 0; index < count; index++) {
152            CFURLRef thisURL = (CFURLRef)CFArrayGetValueAtIndex(
153                dependencyKextAndFolderURLs, index);
154
155            SAFE_RELEASE_NULL(dependencyPath);
156            SAFE_RELEASE_NULL(dependencyAbsURL);
157
158            dependencyAbsURL = CFURLCopyAbsoluteURL(thisURL);
159            if (!dependencyAbsURL) {
160                result = kOSKextReturnNoMemory;
161                goto finish;
162            }
163            dependencyPath = CFURLCopyFileSystemPath(dependencyAbsURL,
164                kCFURLPOSIXPathStyle);
165            if (!dependencyPath) {
166                result = kOSKextReturnNoMemory;
167                goto finish;
168            }
169
170            CFArrayAppendValue(dependencyPaths, dependencyPath);
171        }
172    }
173
174    requestData = CFPropertyListCreateData(kCFAllocatorDefault,
175         requestDict, kCFPropertyListBinaryFormat_v1_0,
176         /* options */ 0,
177         &error);
178    if (!requestData) {
179        // any point in logging error reason here? nothing caller can do....
180        result = kOSKextReturnSerialization;
181        goto finish;
182    }
183
184    result = kextmanager_load_kext(kextd_port,
185        (char *)CFDataGetBytePtr(requestData),
186        CFDataGetLength(requestData));
187
188finish:
189    SAFE_RELEASE(requestData);
190    SAFE_RELEASE(dependencyPaths);
191    SAFE_RELEASE(dependencyPath);
192    SAFE_RELEASE(dependencyAbsURL);
193    SAFE_RELEASE(error);
194
195    return result;
196}
197
198/*********************************************************************
199*********************************************************************/
200OSReturn KextManagerLoadKextWithIdentifier(
201    CFStringRef    kextIdentifier,
202    CFArrayRef     dependencyKextAndFolderURLs)
203{
204    OSReturn               result      = kOSReturnError;
205    CFMutableDictionaryRef requestDict = NULL;  // must release
206
207    if (!kextIdentifier) {
208        result = kOSKextReturnInvalidArgument;
209        goto finish;
210    }
211
212    requestDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
213        /* capacity */ 0, &kCFTypeDictionaryKeyCallBacks,
214        &kCFTypeDictionaryValueCallBacks);
215    if (!requestDict) {
216        result = kOSKextReturnNoMemory;
217        goto finish;
218    }
219
220    CFDictionarySetValue(requestDict, kKextLoadIdentifierKey,
221        kextIdentifier);
222
223    result = __KextManagerSendLoadKextRequest(requestDict,
224        dependencyKextAndFolderURLs);
225
226finish:
227    SAFE_RELEASE(requestDict);
228    return result;
229}
230
231/*********************************************************************
232*********************************************************************/
233OSReturn KextManagerLoadKextWithURL(
234    CFURLRef       kextURL,
235    CFArrayRef     dependencyKextAndFolderURLs)
236{
237    OSReturn               result      = kOSReturnError;
238    CFMutableDictionaryRef requestDict = NULL;  // must release
239    CFURLRef               absURL      = NULL;  // must release
240    CFStringRef            kextPath    = NULL;  // must release
241
242    if (!kextURL) {
243        result = kOSKextReturnInvalidArgument;
244        goto finish;
245    }
246
247    requestDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
248        /* capacity */ 0, &kCFTypeDictionaryKeyCallBacks,
249        &kCFTypeDictionaryValueCallBacks);
250    if (!requestDict) {
251        result = kOSKextReturnNoMemory;
252        goto finish;
253    }
254
255    absURL = CFURLCopyAbsoluteURL(kextURL);
256    if (!absURL) {
257        result = kOSKextReturnNoMemory;
258        goto finish;
259    }
260
261    kextPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
262    if (!kextPath) {
263        result = kOSKextReturnSerialization;
264        goto finish;
265    }
266    CFDictionarySetValue(requestDict, kKextLoadPathKey, kextPath);
267
268    result = __KextManagerSendLoadKextRequest(requestDict,
269        dependencyKextAndFolderURLs);
270
271finish:
272    SAFE_RELEASE(requestDict);
273    SAFE_RELEASE(absURL);
274    SAFE_RELEASE(kextPath);
275    return result;
276}
277
278/*********************************************************************
279*********************************************************************/
280OSReturn KextManagerUnloadKextWithIdentifier(
281    CFStringRef kextIdentifier)
282{
283    OSReturn      result           = kOSReturnError;
284    OSKextLogSpec oldUserLogSpec   = OSKextGetLogFilter(/* kernel? */ false);
285    OSKextLogSpec oldKernelLogSpec = OSKextGetLogFilter(/* kernel? */ true);
286
287    if (!kextIdentifier) {
288        result = kOSKextReturnInvalidArgument;
289        goto finish;
290    }
291
292    OSKextSetLogFilter(kOSKextLogSilentFilter, /* kernelFlag */ false);
293    OSKextSetLogFilter(kOSKextLogSilentFilter, /* kernelFlag */ true);
294
295    result = OSKextUnloadKextWithIdentifier(kextIdentifier,
296        /* terminateServicesAndRemovePersonalities */ TRUE);
297
298finish:
299
300    OSKextSetLogFilter(oldUserLogSpec, /* kernelFlag */ false);
301    OSKextSetLogFilter(oldKernelLogSpec, /* kernelFlag */ true);
302    return result;
303}
304
305/*********************************************************************
306* Use this applier function to strip out any info from the kernel
307* we don't want to expose in public API.
308*********************************************************************/
309void _removePrivateKextInfo(
310    const void * vKey __unused,
311    const void * vValue,
312          void * vContext __unused)
313{
314    CFMutableDictionaryRef kextInfo = (CFMutableDictionaryRef)vValue;
315    CFDictionaryRemoveValue(kextInfo, CFSTR("OSBundleMachOHeaders"));
316    return;
317}
318
319/*********************************************************************
320*********************************************************************/
321CFDictionaryRef KextManagerCopyLoadedKextInfo(
322    CFArrayRef  kextIdentifiers,
323    CFArrayRef  infoKeys)
324{
325    CFMutableDictionaryRef result     = NULL;
326    CFDictionaryRef        kextResult = NULL;  // must release
327
328    kextResult = OSKextCopyLoadedKextInfo(kextIdentifiers, infoKeys);
329    if (!kextResult) {
330        goto finish;
331    }
332
333   /* Copy and remove properties we don't want people to use.
334    */
335    result = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, kextResult);
336    CFDictionaryApplyFunction(result, &_removePrivateKextInfo, /* context */ NULL);
337
338finish:
339    SAFE_RELEASE(kextResult);
340    return (CFDictionaryRef)result;
341}
342
343/*********************************************************************
344*********************************************************************/
345CFArrayRef _KextManagerCreatePropertyValueArray(
346    CFAllocatorRef allocator __unused,
347    CFStringRef    propertyKey)
348{
349    CFMutableArrayRef valueArray = NULL;  // returned
350    CFDataRef         xmlData = NULL;  // must release
351    CFTypeRef	      cfObj;
352
353    kern_return_t kern_result = kOSReturnError;
354    property_key_t property_key = "";  // matches prop_key_t in .defs file
355
356    mach_port_t   kextd_port = MACH_PORT_NULL;
357
358    char      * xml_data = NULL;  // must vm_deallocate()
359    natural_t   xml_data_length = 0;
360
361    CFErrorRef error = NULL;  // must release
362
363    if (!propertyKey || PROPERTYKEY_LEN <
364	    (CFStringGetMaximumSizeForEncoding(CFStringGetLength(propertyKey),
365	    kCFStringEncodingUTF8))) {
366        goto finish;
367    }
368
369    if (!CFStringGetCString(propertyKey,
370        property_key, sizeof(property_key) - 1, kCFStringEncodingUTF8)) {
371        goto finish;
372    }
373
374    kern_result = get_kextd_port(&kextd_port);
375    if (kern_result != kOSReturnSuccess) {
376        goto finish;
377    }
378
379    kern_result = kextmanager_create_property_value_array(kextd_port,
380        property_key, &xml_data, &xml_data_length);
381    if (kern_result != kOSReturnSuccess) {
382        goto finish;
383    }
384
385    xmlData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (UInt8 *)xml_data,
386        xml_data_length, kCFAllocatorNull);
387    if (!xmlData) {
388        goto finish;
389    }
390
391    cfObj = CFPropertyListCreateWithData(kCFAllocatorDefault,
392        xmlData, /* options */ 0, /* format */ NULL, &error);
393    if (!cfObj) {
394        // any point in logging error reason here? nothing caller can do....
395        goto finish;
396    }
397
398    if (CFGetTypeID(cfObj) != CFArrayGetTypeID()) {
399        CFRelease(cfObj);
400        goto finish;
401    }
402    valueArray = (CFMutableArrayRef) cfObj;
403
404finish:
405
406    SAFE_RELEASE(error);
407    SAFE_RELEASE(xmlData);
408
409    if (xml_data) {
410        vm_deallocate(mach_task_self(), (vm_address_t)xml_data,
411            xml_data_length);
412    }
413    return valueArray;
414}
415
416/*********************************************************************
417*********************************************************************/
418static kern_return_t get_kextd_port(mach_port_t * kextd_port)
419{
420    kern_return_t kern_result = kOSReturnError;
421    mach_port_t   bootstrap_port = MACH_PORT_NULL;
422
423    kern_result = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
424    if (kern_result == kOSReturnSuccess) {
425        kern_result = bootstrap_look_up2(bootstrap_port,
426                                         (char *)KEXTD_SERVER_NAME,
427                                         kextd_port,
428                                         0,
429                                         BOOTSTRAP_PRIVILEGED_SERVER);
430    }
431
432    return kern_result;
433}
434