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 <CoreFoundation/CoreFoundation.h> 29 30#include <mach/mach.h> 31#include <mach/mach_port.h> 32#include <servers/bootstrap.h> 33#include <sysexits.h> 34 35#include <IOKit/kext/OSKext.h> 36#include "kext_tools_util.h" 37#include "kextd_globals.h" 38#include "kextd_mig_server.h" 39 40/* mig-generated externals and functions */ 41extern struct mig_subsystem _kextmanager_subsystem; 42extern boolean_t kextmanager_server(mach_msg_header_t *, mach_msg_header_t *); 43 44extern struct mig_subsystem svc_kextd_kernel_request_subsystem; 45extern boolean_t kextd_kernel_request_server( 46 mach_msg_header_t *InHeadP, 47 mach_msg_header_t *OutHeadP); 48 49uid_t gClientUID = -1; 50 51/******************************************************************************* 52*******************************************************************************/ 53boolean_t kextd_demux( 54 mach_msg_header_t * request, 55 mach_msg_header_t * reply) 56{ 57 boolean_t processed = FALSE; 58 59 mach_msg_format_0_trailer_t * trailer; 60 61 /* Feed the request into the ("MiG" generated) server. We have two 62 * subsystems, one for user-space clients, one for the kernel. 63 */ 64 if (!processed) { 65 if (request->msgh_id >= _kextmanager_subsystem.start && 66 request->msgh_id < _kextmanager_subsystem.end) { 67 68 /* 69 * Get the caller's credentials (eUID/eGID) from the message trailer. 70 */ 71 trailer = (mach_msg_security_trailer_t *)((vm_offset_t)request + 72 round_msg(request->msgh_size)); 73 74 if ((trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0) && 75 (trailer->msgh_trailer_size >= MACH_MSG_TRAILER_FORMAT_0_SIZE)) { 76 77 gClientUID = trailer->msgh_sender.val[0]; 78 79 OSKextLog(/* kext */ NULL, 80 kOSKextLogDebugLevel | kOSKextLogIPCFlag, 81 "MIG message received: caller has eUID = %d, eGID = %d.", 82 trailer->msgh_sender.val[0], 83 trailer->msgh_sender.val[1]); 84 85 } else { 86 OSKextLog(/* kext */ NULL, 87 kOSKextLogWarningLevel | kOSKextLogIPCFlag, 88 "Caller's credentials not available."); 89 gClientUID = -1; 90 91 } 92 93 /* Process user task requests. 94 */ 95 processed = kextmanager_server(request, reply); 96 97 } else if (request->msgh_id >= svc_kextd_kernel_request_subsystem.start && 98 request->msgh_id < svc_kextd_kernel_request_subsystem.end) { 99 100 /* Process kernel requests. 101 */ 102 processed = kextd_kernel_request_server(request, reply); 103 } 104 } 105 106 if (!processed) { 107 if (request->msgh_id >= MACH_NOTIFY_FIRST && 108 request->msgh_id < MACH_NOTIFY_LAST) { 109 110 OSKextLog(/* kext */ NULL, 111 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 112 "Failed to process MIG message."); 113 } else { 114 OSKextLog(/* kext */ NULL, 115 kOSKextLogErrorLevel | kOSKextLogIPCFlag, 116 "Unknown MIG message received."); 117 } 118 } 119 120 gClientUID = (uid_t)-1; 121 122 return processed; 123} 124 125/******************************************************************************* 126*******************************************************************************/ 127void kextd_mach_port_callback( 128 CFMachPortRef port, 129 void *msg, 130 CFIndex size, 131 void *info) 132{ 133 mig_reply_error_t * bufRequest = msg; 134 mig_reply_error_t * bufReply = CFAllocatorAllocate( 135 NULL, _kextmanager_subsystem.maxsize, 0); 136 mach_msg_return_t mr; 137 int options; 138 139 /* we have a request message */ 140 (void) kextd_demux(&bufRequest->Head, &bufReply->Head); 141 142 if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && 143 (bufReply->RetCode != KERN_SUCCESS)) { 144 145 if (bufReply->RetCode == MIG_NO_REPLY) { 146 /* 147 * This return code is a little tricky -- it appears that the 148 * demux routine found an error of some sort, but since that 149 * error would not normally get returned either to the local 150 * user or the remote one, we pretend it's ok. 151 */ 152 CFAllocatorDeallocate(NULL, bufReply); 153 return; 154 } 155 156 /* 157 * destroy any out-of-line data in the request buffer but don't destroy 158 * the reply port right (since we need that to send an error message). 159 */ 160 bufRequest->Head.msgh_remote_port = MACH_PORT_NULL; 161 mach_msg_destroy(&bufRequest->Head); 162 } 163 164 if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) { 165 /* no reply port, so destroy the reply */ 166 if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 167 mach_msg_destroy(&bufReply->Head); 168 } 169 CFAllocatorDeallocate(NULL, bufReply); 170 return; 171 } 172 173 /* 174 * send reply. 175 * 176 * We don't want to block indefinitely because the client 177 * isn't receiving messages from the reply port. 178 * If we have a send-once right for the reply port, then 179 * this isn't a concern because the send won't block. 180 * If we have a send right, we need to use MACH_SEND_TIMEOUT. 181 * To avoid falling off the kernel's fast RPC path unnecessarily, 182 * we only supply MACH_SEND_TIMEOUT when absolutely necessary. 183 */ 184 185 options = MACH_SEND_MSG; 186 if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) { 187 options |= MACH_SEND_TIMEOUT; 188 } 189 mr = mach_msg(&bufReply->Head, /* msg */ 190 options, /* option */ 191 bufReply->Head.msgh_size, /* send_size */ 192 0, /* rcv_size */ 193 MACH_PORT_NULL, /* rcv_name */ 194 MACH_MSG_TIMEOUT_NONE, /* timeout */ 195 MACH_PORT_NULL); /* notify */ 196 197 198 /* Has a message error occurred? */ 199 switch (mr) { 200 case MACH_SEND_INVALID_DEST: 201 case MACH_SEND_TIMED_OUT: 202 /* the reply can't be delivered, so destroy it */ 203 mach_msg_destroy(&bufReply->Head); 204 break; 205 206 default : 207 /* Includes success case. */ 208 break; 209 } 210 211 CFAllocatorDeallocate(NULL, bufReply); 212} 213