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 <mach/mach_port.h> 29 30#include <IOKit/kext/OSKext.h> 31#include "kext_tools_util.h" 32#include "kextd_globals.h" 33#include <dispatch/dispatch.h> 34 35dispatch_source_t _gKextutilLock = NULL; 36 37void kextd_process_kernel_requests(void); 38 39/****************************************************************************** 40 * _kextmanager_lock_volume tries to lock volumes for clients (kextutil) 41 *****************************************************************************/ 42static void removeKextutilLock(void) 43{ 44 if (_gKextutilLock) { 45 dispatch_source_cancel(_gKextutilLock); 46 } 47 48 if (gKernelRequestsPending) { 49 kextd_process_kernel_requests(); 50 } 51 52 CFRunLoopWakeUp(CFRunLoopGetCurrent()); 53 return; 54} 55 56/****************************************************************************** 57 * _kextmanager_lock_volume tries to lock volumes for clients (kextutil) 58 *****************************************************************************/ 59kern_return_t _kextmanager_lock_kextload( 60 mach_port_t server, 61 mach_port_t client, 62 int * lockstatus) 63{ 64 kern_return_t mig_result = KERN_FAILURE; 65 int result; 66 67 if (!lockstatus) { 68 OSKextLog(/* kext */ NULL, 69 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 70 "kextmanager_lock_kextload requires non-NULL lockstatus."); 71 mig_result = KERN_SUCCESS; 72 result = EINVAL; 73 goto finish; 74 } 75 76 if (gClientUID != 0) { 77 OSKextLog(/* kext */ NULL, 78 kOSKextLogErrorLevel, 79 "Non-root process doesn't need to lock as it will fail to load."); 80 mig_result = KERN_SUCCESS; 81 result = EPERM; 82 goto finish; 83 } 84 85 if (_gKextutilLock) { 86 mig_result = KERN_SUCCESS; 87 result = EBUSY; 88 goto finish; 89 } 90 91 result = ENOMEM; 92 93 _gKextutilLock = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, client, 94 DISPATCH_MACH_SEND_DEAD, dispatch_get_main_queue()); 95 96 if (_gKextutilLock) { 97 98 dispatch_source_set_event_handler(_gKextutilLock, ^{ 99 OSKextLog(/* kext */ NULL, 100 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 101 "Client exited without releasing kextutil lock."); 102 removeKextutilLock(); 103 }); 104 105 dispatch_source_set_cancel_handler(_gKextutilLock, ^{ 106 dispatch_release(_gKextutilLock); 107 mach_port_deallocate(mach_task_self(), client); 108 _gKextutilLock = NULL; 109 }); 110 111 dispatch_resume(_gKextutilLock); 112 113 mig_result = KERN_SUCCESS; 114 result = 0; 115 } 116 117finish: 118 if (mig_result != KERN_SUCCESS) { 119 if (gClientUID == 0) { 120 OSKextLog(/* kext */ NULL, 121 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 122 "Trouble while locking for kextutil - %s.", 123 safe_mach_error_string(mig_result)); 124 } 125 removeKextutilLock(); 126 } else if (lockstatus) { 127 *lockstatus = result; // only meaningful if mig_result == KERN_SUCCESS 128 } 129 130 return mig_result; 131} 132 133/****************************************************************************** 134 * _kextmanager_unlock_kextload unlocks for clients (kextutil) 135 *****************************************************************************/ 136kern_return_t _kextmanager_unlock_kextload( 137 mach_port_t server, 138 mach_port_t client) 139{ 140 kern_return_t mig_result = KERN_FAILURE; 141 142 if (gClientUID != 0) { 143 OSKextLog(/* kext */ NULL, 144 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 145 "Non-root kextutil doesn't need to lock/unlock."); 146 mig_result = KERN_SUCCESS; 147 goto finish; 148 } 149 150 if (client != (mach_port_t)dispatch_source_get_handle(_gKextutilLock)) { 151 OSKextLog(/* kext */ NULL, 152 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 153 "%d not used to lock for kextutil.", client); 154 goto finish; 155 } 156 157 removeKextutilLock(); 158 159 mig_result = KERN_SUCCESS; 160 161finish: 162 // we don't need the extra send right added by MiG 163 mach_port_deallocate(mach_task_self(), client); 164 165 return mig_result; 166} 167 168