CFMessagePort.c
1 /* CFMessagePort.c 2 Copyright (c) 1998-2019, Apple Inc. and the Swift project authors 3 4 Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors 5 Licensed under Apache License v2.0 with Runtime Library Exception 6 See http://swift.org/LICENSE.txt for license information 7 See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 8 Responsibility: Michael LeHew 9 */ 10 11 #include <CoreFoundation/CFBase.h> 12 #include <CoreFoundation/CFMessagePort.h> 13 #include <CoreFoundation/CFRunLoop.h> 14 #include <CoreFoundation/CFMachPort.h> 15 #include <CoreFoundation/CFDictionary.h> 16 #include <CoreFoundation/CFByteOrder.h> 17 #include <assert.h> 18 #include <limits.h> 19 #include "CFInternal.h" 20 #include "CFRuntime_Internal.h" 21 #include <mach/mach.h> 22 #include <mach/message.h> 23 #include <mach/mach_error.h> 24 #include "CFMachPort_Internal.h" 25 #include "CFMachPort_Lifetime.h" 26 #include <math.h> 27 #include <mach/mach_time.h> 28 #include <dlfcn.h> 29 #if __HAS_DISPATCH__ 30 #include <dispatch/dispatch.h> 31 #if TARGET_OS_MAC && __has_include(<dispatch/private.h>) 32 #include <dispatch/private.h> 33 #endif 34 #endif 35 36 #if TARGET_OS_MAC 37 #include <bootstrap.h> 38 #endif 39 40 extern pid_t getpid(void); 41 42 #define __kCFMessagePortMaxNameLengthMax 255 43 44 #if defined(BOOTSTRAP_MAX_NAME_LEN) 45 #define __kCFMessagePortMaxNameLength BOOTSTRAP_MAX_NAME_LEN 46 #else 47 #define __kCFMessagePortMaxNameLength 128 48 #endif 49 50 #if __kCFMessagePortMaxNameLengthMax < __kCFMessagePortMaxNameLength 51 #undef __kCFMessagePortMaxNameLength 52 #define __kCFMessagePortMaxNameLength __kCFMessagePortMaxNameLengthMax 53 #endif 54 55 #define __CFMessagePortMaxDataSize 0x60000000L 56 57 static os_unfair_lock __CFAllMessagePortsLock = OS_UNFAIR_LOCK_INIT; 58 static CFMutableDictionaryRef __CFAllLocalMessagePorts = NULL; 59 static CFMutableDictionaryRef __CFAllRemoteMessagePorts = NULL; 60 61 struct __CFMessagePort { 62 CFRuntimeBase _base; 63 CFLock_t _lock; 64 CFStringRef _name; 65 CFMachPortRef _port; /* immutable; invalidated */ 66 CFMutableDictionaryRef _replies; 67 int32_t _convCounter; 68 int32_t _perPID; /* zero if not per-pid, else pid */ 69 CFMachPortRef _replyPort; /* only used by remote port; immutable once created; invalidated */ 70 CFRunLoopSourceRef _source; /* only used by local port; immutable once created; invalidated */ 71 dispatch_source_t _dispatchSource; /* only used by local port; invalidated */ 72 dispatch_queue_t _dispatchQ; /* only used by local port */ 73 CFMessagePortInvalidationCallBack _icallout; 74 CFMessagePortCallBack _callout; /* only used by local port; immutable */ 75 CFMessagePortCallBackEx _calloutEx; /* only used by local port; immutable */ 76 CFMessagePortContext _context; /* not part of remote port; immutable; invalidated */ 77 }; 78 79 /* Bit 0 in the base reserved bits is used for invalid state */ 80 /* Bit 1 of the base reserved bits is used for has-extra-port-refs state */ 81 /* Bit 2 of the base reserved bits is used for is-remote state */ 82 /* Bit 3 in the base reserved bits is used for is-deallocing state */ 83 84 CF_INLINE Boolean __CFMessagePortIsValid(CFMessagePortRef ms) { 85 return __CFRuntimeGetFlag(ms, 0); 86 } 87 88 CF_INLINE void __CFMessagePortSetValid(CFMessagePortRef ms) { 89 __CFRuntimeSetFlag(ms, 0, true); 90 } 91 92 CF_INLINE void __CFMessagePortUnsetValid(CFMessagePortRef ms) { 93 __CFRuntimeSetFlag(ms, 0, false); 94 } 95 96 CF_INLINE Boolean __CFMessagePortExtraMachRef(CFMessagePortRef ms) { 97 return __CFRuntimeGetFlag(ms, 1); 98 } 99 100 CF_INLINE void __CFMessagePortSetExtraMachRef(CFMessagePortRef ms) { 101 __CFRuntimeSetFlag(ms, 1, true); 102 } 103 104 CF_INLINE void __CFMessagePortUnsetExtraMachRef(CFMessagePortRef ms) { 105 __CFRuntimeSetFlag(ms, 1, false); 106 } 107 108 CF_INLINE Boolean __CFMessagePortIsRemote(CFMessagePortRef ms) { 109 return __CFRuntimeGetFlag(ms, 2); 110 } 111 112 CF_INLINE void __CFMessagePortSetRemote(CFMessagePortRef ms) { 113 __CFRuntimeSetFlag(ms, 2, true); 114 } 115 116 CF_INLINE void __CFMessagePortUnsetRemote(CFMessagePortRef ms) { 117 __CFRuntimeSetFlag(ms, 2, false); 118 } 119 120 CF_INLINE Boolean __CFMessagePortIsDeallocing(CFMessagePortRef ms) { 121 return __CFRuntimeGetFlag(ms, 3); 122 } 123 124 CF_INLINE void __CFMessagePortSetIsDeallocing(CFMessagePortRef ms) { 125 __CFRuntimeSetFlag(ms, 3, true); 126 } 127 128 CF_INLINE void __CFMessagePortLock(CFMessagePortRef ms) { 129 __CFLock(&(ms->_lock)); 130 } 131 132 CF_INLINE void __CFMessagePortUnlock(CFMessagePortRef ms) { 133 __CFUnlock(&(ms->_lock)); 134 } 135 136 // Just a heuristic 137 #define __CFMessagePortMaxInlineBytes ((int32_t)4000) 138 139 struct __CFMessagePortMachMessage { 140 mach_msg_base_t base; 141 mach_msg_ool_descriptor_t ool; 142 struct innards { 143 int32_t magic; 144 int32_t msgid; 145 int32_t convid; 146 int32_t byteslen; 147 uint8_t bytes[0]; 148 } innards; 149 }; 150 151 #define CFMP_MSGH_ID_64 0x63666d70 // 'cfmp' 152 #define CFMP_MSGH_ID_32 0x43464d50 // 'CFMP' 153 #if TARGET_RT_64_BIT 154 #define CFMP_MSGH_ID CFMP_MSGH_ID_64 155 #else 156 #define CFMP_MSGH_ID CFMP_MSGH_ID_32 157 #endif 158 159 // NOTE: mach_msg_ool_descriptor_t has different sizes based on 32/64-bit for send/receive 160 #define __INNARD_OFFSET (((!(msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && ((mach_msg_header_t *)msgp)->msgh_id == CFMP_MSGH_ID_32) || ( (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && !TARGET_RT_64_BIT)) ? 40 : 44) 161 162 #define MAGIC 0xF0F2F4F8 163 164 // These 3 macros should ONLY be used on RECEIVED messages, not ones being constructed on the sending side 165 #define MSGP_GET(msgp, ident) (((struct __CFMessagePortMachMessage *)msgp)->ident) 166 #define MSGP_INFO(msgp, ident) ((struct innards *)((void *)msgp + __INNARD_OFFSET))->ident 167 #define MSGP_SIZE(msgp) (__INNARD_OFFSET + sizeof(struct innards)) 168 169 170 static mach_msg_base_t *__CFMessagePortCreateMessage(bool reply, mach_port_t port, mach_port_t replyPort, int32_t convid, int32_t msgid, const uint8_t *bytes, int32_t byteslen) { 171 if (__CFMessagePortMaxDataSize < byteslen) return NULL; 172 if (byteslen < -1) return NULL; 173 int32_t rounded_byteslen = (byteslen < 0) ? 0 : ((byteslen + 7) & ~0x7); 174 int32_t size = (int32_t)sizeof(struct __CFMessagePortMachMessage) + ((rounded_byteslen <= __CFMessagePortMaxInlineBytes) ? rounded_byteslen : 0); 175 struct __CFMessagePortMachMessage *msg = CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); 176 if (!msg) return NULL; 177 memset(msg, 0, size); 178 msg->base.header.msgh_id = CFMP_MSGH_ID; 179 msg->base.header.msgh_size = size; 180 msg->base.header.msgh_remote_port = port; 181 msg->base.header.msgh_local_port = replyPort; 182 msg->base.header.msgh_bits = MACH_MSGH_BITS((reply ? MACH_MSG_TYPE_MOVE_SEND_ONCE : MACH_MSG_TYPE_COPY_SEND), (MACH_PORT_NULL != replyPort ? MACH_MSG_TYPE_MAKE_SEND_ONCE : 0)); 183 msg->base.body.msgh_descriptor_count = 0; 184 msg->innards.magic = MAGIC; 185 msg->innards.msgid = CFSwapInt32HostToLittle(msgid); 186 msg->innards.convid = CFSwapInt32HostToLittle(convid); 187 msg->innards.byteslen = CFSwapInt32HostToLittle(byteslen); 188 if (rounded_byteslen <= __CFMessagePortMaxInlineBytes) { 189 if (NULL != bytes && 0 < byteslen) { 190 memmove(msg->innards.bytes, bytes, byteslen); 191 } 192 } else { 193 msg->base.header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; 194 msg->base.body.msgh_descriptor_count = 1; 195 msg->ool.deallocate = false; 196 msg->ool.copy = MACH_MSG_VIRTUAL_COPY; 197 msg->ool.address = (void *)bytes; 198 msg->ool.size = byteslen; 199 msg->ool.type = MACH_MSG_OOL_DESCRIPTOR; 200 } 201 return (mach_msg_base_t *)msg; 202 } 203 204 static CFStringRef __CFMessagePortCopyDescription(CFTypeRef cf) { 205 CFMessagePortRef ms = (CFMessagePortRef)cf; 206 CFStringRef result; 207 const char *locked; 208 CFStringRef contextDesc = NULL; 209 locked = "Maybe"; 210 if (__CFMessagePortIsRemote(ms)) { 211 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFMessagePort %p [%p]>{locked = %s, valid = %s, remote = %s, name = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name); 212 } else { 213 if (NULL != ms->_context.info && NULL != ms->_context.copyDescription) { 214 contextDesc = ms->_context.copyDescription(ms->_context.info); 215 } 216 if (NULL == contextDesc) { 217 contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFMessagePort context %p>"), ms->_context.info); 218 } 219 void *addr = ms->_callout ? (void *)ms->_callout : (void *)ms->_calloutEx; 220 Dl_info info; 221 const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; 222 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFMessagePort %p [%p]>{locked = %s, valid = %s, remote = %s, name = %@, source = %p, callout = %s (%p), context = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name, ms->_source, name, addr, (NULL != contextDesc ? contextDesc : CFSTR("<no description>"))); 223 } 224 if (NULL != contextDesc) { 225 CFRelease(contextDesc); 226 } 227 return result; 228 } 229 230 static void __CFMessagePortDeallocate(CFTypeRef cf) { 231 CFMessagePortRef ms = (CFMessagePortRef)cf; 232 __CFMessagePortSetIsDeallocing(ms); 233 CFMessagePortInvalidate(ms); 234 // Delay cleanup of _replies until here so that invalidation during 235 // SendRequest does not cause _replies to disappear out from under that function. 236 if (NULL != ms->_replies) { 237 CFRelease(ms->_replies); 238 } 239 if (NULL != ms->_name) { 240 CFRelease(ms->_name); 241 } 242 if (NULL != ms->_port) { 243 mach_port_t const mp = CFMachPortGetPort(ms->_port); 244 if (__CFMessagePortExtraMachRef(ms)) { 245 _cfmp_record_deallocation(_CFMPLifetimeClientCFMessagePort, mp, true /*doSend*/, true /*doReceive*/); 246 } 247 CFMachPortInvalidate(ms->_port); 248 CFRelease(ms->_port); 249 } 250 251 // A remote message port for a local message port in the same process will get the 252 // same mach port, and the remote port will keep the mach port from being torn down, 253 // thus keeping the remote port from getting any sort of death notification and 254 // auto-invalidating; so we manually implement the 'auto-invalidation' here by 255 // tickling each remote port to check its state after any message port is destroyed, 256 // but most importantly after local message ports are destroyed. 257 os_unfair_lock_lock(&__CFAllMessagePortsLock); 258 CFMessagePortRef *remotePorts = NULL; 259 CFIndex cnt = 0; 260 if (NULL != __CFAllRemoteMessagePorts) { 261 cnt = CFDictionaryGetCount(__CFAllRemoteMessagePorts); 262 remotePorts = CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFMessagePortRef), 0); 263 CFDictionaryGetKeysAndValues(__CFAllRemoteMessagePorts, NULL, (const void **)remotePorts); 264 for (CFIndex idx = 0; idx < cnt; idx++) { 265 CFRetain(remotePorts[idx]); 266 } 267 } 268 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 269 if (remotePorts) { 270 for (CFIndex idx = 0; idx < cnt; idx++) { 271 // as a side-effect, this will auto-invalidate the CFMessagePort if the CFMachPort is invalid 272 CFMessagePortIsValid(remotePorts[idx]); 273 CFRelease(remotePorts[idx]); 274 } 275 CFAllocatorDeallocate(kCFAllocatorSystemDefault, remotePorts); 276 } 277 } 278 279 const CFRuntimeClass __CFMessagePortClass = { 280 0, 281 "CFMessagePort", 282 NULL, // init 283 NULL, // copy 284 __CFMessagePortDeallocate, 285 NULL, 286 NULL, 287 NULL, // 288 __CFMessagePortCopyDescription 289 }; 290 291 CFTypeID CFMessagePortGetTypeID(void) { 292 return _kCFRuntimeIDCFMessagePort; 293 } 294 295 static CFStringRef __CFMessagePortCreateSanitizedStringName(CFStringRef name, uint8_t **utfnamep, CFIndex *utfnamelenp) { 296 uint8_t *utfname; 297 CFIndex utflen; 298 CFStringRef result = NULL; 299 utfname = CFAllocatorAllocate(kCFAllocatorSystemDefault, __kCFMessagePortMaxNameLength + 1, 0); 300 CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUTF8, 0, false, utfname, __kCFMessagePortMaxNameLength, &utflen); 301 utfname[utflen] = '\0'; 302 if (strlen((const char *)utfname) != utflen) { 303 /* PCA 9194709: refuse to sanitize a string with an embedded nul character */ 304 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 305 utfname = NULL; 306 utfnamelenp = 0; 307 } else { 308 /* A new string is created, because the original string may have been 309 truncated to the max length, and we want the string name to definitely 310 match the raw UTF-8 chunk that has been created. Also, this is useful 311 to get a constant string in case the original name string was mutable. */ 312 result = CFStringCreateWithBytes(kCFAllocatorSystemDefault, utfname, utflen, kCFStringEncodingUTF8, false); 313 } 314 if (NULL != utfnamep) { 315 *utfnamep = utfname; 316 } else if (NULL != utfname) { 317 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 318 } 319 if (NULL != utfnamelenp) { 320 *utfnamelenp = utflen; 321 } 322 return result; 323 } 324 325 static void __CFMessagePortDummyCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) { 326 // not supposed to be implemented 327 } 328 329 static void __CFMessagePortInvalidationCallBack(CFMachPortRef port, void *info) { 330 // info has been setup as the CFMessagePort owning the CFMachPort 331 if (info) CFMessagePortInvalidate(info); 332 } 333 334 static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef inName, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo, Boolean perPID, CFMessagePortCallBackEx calloutEx) { 335 CFMessagePortRef memory; 336 uint8_t *utfname = NULL; 337 338 if (shouldFreeInfo) *shouldFreeInfo = true; 339 340 CFStringRef name = NULL; 341 if (inName != NULL) { 342 name = __CFMessagePortCreateSanitizedStringName(inName, &utfname, NULL); 343 } 344 345 os_unfair_lock_lock(&__CFAllMessagePortsLock); 346 if (!perPID && NULL != name) { 347 CFMessagePortRef existing; 348 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { 349 CFRetain(existing); 350 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 351 CFRelease(name); 352 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 353 if (!CFMessagePortIsValid(existing)) { // must do this outside lock to avoid deadlock 354 CFRelease(existing); 355 existing = NULL; 356 } 357 return (CFMessagePortRef)(existing); 358 } 359 } 360 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 361 CFIndex size = sizeof(struct __CFMessagePort) - sizeof(CFRuntimeBase); 362 memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, CFMessagePortGetTypeID(), size, NULL); 363 if (NULL == memory) { 364 if (NULL != name) { 365 CFRelease(name); 366 } 367 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 368 return NULL; 369 } 370 __CFMessagePortUnsetValid(memory); 371 __CFMessagePortUnsetExtraMachRef(memory); 372 __CFMessagePortUnsetRemote(memory); 373 memory->_lock = CFLockInit; 374 memory->_name = name; 375 if (perPID) { 376 memory->_perPID = getpid(); // actual value not terribly useful for local ports 377 } 378 memory->_callout = callout; 379 memory->_calloutEx = calloutEx; 380 381 // sadly this is mostly a repeat of SetName function below sans locks... 382 if (NULL != name) { 383 CFMachPortRef native = NULL; 384 kern_return_t ret; 385 mach_port_t mp; 386 if (!perPID) { 387 } 388 if (!native) { 389 CFMachPortContext ctx = {0, memory, NULL, NULL, NULL}; 390 native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); 391 if (!native) { 392 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 393 // name is released by deallocation 394 CFRelease(memory); 395 return NULL; 396 } 397 mp = CFMachPortGetPort(native); 398 } 399 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); 400 memory->_port = native; 401 } 402 403 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 404 __CFMessagePortSetValid(memory); 405 if (NULL != context) { 406 memmove(&memory->_context, context, sizeof(CFMessagePortContext)); 407 memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; 408 } 409 os_unfair_lock_lock(&__CFAllMessagePortsLock); 410 if (!perPID && NULL != name) { 411 CFMessagePortRef existing; 412 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { 413 CFRetain(existing); 414 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 415 CFRelease(memory); 416 return (CFMessagePortRef)(existing); 417 } 418 if (NULL == __CFAllLocalMessagePorts) { 419 __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 420 } 421 CFDictionaryAddValue(__CFAllLocalMessagePorts, name, memory); 422 } 423 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 424 if (shouldFreeInfo) *shouldFreeInfo = false; 425 return memory; 426 } 427 428 CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { 429 return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, false, NULL); 430 } 431 432 CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { 433 return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, true, NULL); 434 } 435 436 CFMessagePortRef _CFMessagePortCreateLocalEx(CFAllocatorRef allocator, CFStringRef name, Boolean perPID, uintptr_t unused, CFMessagePortCallBackEx calloutEx, CFMessagePortContext *context, Boolean *shouldFreeInfo) { 437 return __CFMessagePortCreateLocal(allocator, name, NULL, context, shouldFreeInfo, perPID, calloutEx); 438 } 439 440 static CFMessagePortRef __CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef inName, Boolean perPID, CFIndex pid) { 441 CFMessagePortRef memory; 442 CFMachPortRef native; 443 CFMachPortContext ctx; 444 uint8_t *utfname = NULL; 445 CFIndex size; 446 mach_port_t port = MACH_PORT_NULL; 447 448 CFStringRef const name = __CFMessagePortCreateSanitizedStringName(inName, &utfname, NULL); 449 if (NULL == name) { 450 return NULL; 451 } 452 os_unfair_lock_lock(&__CFAllMessagePortsLock); 453 if (!perPID && NULL != name) { 454 CFMessagePortRef existing; 455 if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) { 456 CFRetain(existing); 457 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 458 CFRelease(name); 459 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 460 if (!CFMessagePortIsValid(existing)) { // must do this outside lock to avoid deadlock 461 CFRelease(existing); 462 existing = NULL; 463 } 464 return (CFMessagePortRef)(existing); 465 } 466 } 467 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 468 size = sizeof(struct __CFMessagePort) - sizeof(CFMessagePortContext) - sizeof(CFRuntimeBase); 469 memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, CFMessagePortGetTypeID(), size, NULL); 470 if (NULL == memory) { 471 if (NULL != name) { 472 CFRelease(name); 473 } 474 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 475 return NULL; 476 } 477 __CFMessagePortUnsetValid(memory); 478 __CFMessagePortUnsetExtraMachRef(memory); 479 __CFMessagePortSetRemote(memory); 480 memory->_lock = CFLockInit; 481 memory->_name = name; 482 memory->_replies = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); 483 if (perPID) { 484 memory->_perPID = pid; 485 } 486 ctx.version = 0; 487 ctx.info = memory; 488 ctx.retain = NULL; 489 ctx.release = NULL; 490 ctx.copyDescription = NULL; 491 native = CFMachPortCreateWithPort(allocator, port, __CFMessagePortDummyCallback, &ctx, NULL); 492 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 493 if (NULL == native) { 494 // name is released by deallocation 495 CFRelease(memory); 496 return NULL; 497 } 498 memory->_port = native; 499 __CFMessagePortSetValid(memory); 500 os_unfair_lock_lock(&__CFAllMessagePortsLock); 501 if (!perPID && NULL != name) { 502 CFMessagePortRef existing; 503 if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) { 504 CFRetain(existing); 505 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 506 CFRelease(memory); 507 return (CFMessagePortRef)(existing); 508 } 509 if (NULL == __CFAllRemoteMessagePorts) { 510 __CFAllRemoteMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 511 } 512 CFDictionaryAddValue(__CFAllRemoteMessagePorts, name, memory); 513 } 514 CFRetain(native); 515 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 516 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); 517 // that set-invalidation-callback might have called back into us 518 // if the CFMachPort is already bad, but that was a no-op since 519 // there was no callback setup at the (previous) time the CFMachPort 520 // went invalid; so check for validity manually and react 521 if (!CFMachPortIsValid(native)) { 522 CFRelease(memory); // does the invalidate 523 CFRelease(native); 524 return NULL; 525 } 526 CFRelease(native); 527 return (CFMessagePortRef)memory; 528 } 529 530 CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) { 531 return __CFMessagePortCreateRemote(allocator, name, false, 0); 532 } 533 534 CFMessagePortRef CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator, CFStringRef name, CFIndex pid) { 535 return __CFMessagePortCreateRemote(allocator, name, true, pid); 536 } 537 538 Boolean CFMessagePortIsRemote(CFMessagePortRef ms) { 539 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 540 return __CFMessagePortIsRemote(ms); 541 } 542 543 CFStringRef CFMessagePortGetName(CFMessagePortRef ms) { 544 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 545 return ms->_name; 546 } 547 548 Boolean CFMessagePortSetName(CFMessagePortRef ms, CFStringRef inName) { 549 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 550 CFAllocatorRef allocator = CFGetAllocator(ms); 551 uint8_t *utfname = NULL; 552 553 if (ms->_perPID || __CFMessagePortIsRemote(ms)) return false; 554 CFStringRef const name = __CFMessagePortCreateSanitizedStringName(inName, &utfname, NULL); 555 if (NULL == name) { 556 return false; 557 } 558 559 os_unfair_lock_lock(&__CFAllMessagePortsLock); 560 if (NULL != name) { 561 CFMessagePortRef existing; 562 if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { 563 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 564 CFRelease(name); 565 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 566 return false; 567 } 568 } 569 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 570 571 572 __CFMessagePortLock(ms); 573 if (ms->_dispatchSource) { 574 CFLog(kCFLogLevelDebug, CFSTR("*** CFMessagePort: Unable to SetName on CFMessagePort %p as it already has a dispatch queue associated with itself."), ms); 575 __CFMessagePortUnlock(ms); 576 CFRelease(name); 577 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 578 return false; 579 } 580 581 582 if (NULL != name && (NULL == ms->_name || !CFEqual(ms->_name, name))) { 583 CFMachPortRef oldPort = ms->_port; 584 Boolean const previousNameHadExtraRef = ms->_name != NULL && __CFMessagePortExtraMachRef(ms); 585 CFMachPortRef native = NULL; 586 kern_return_t ret; 587 mach_port_t bs, mp; 588 task_get_bootstrap_port(mach_task_self(), &bs); 589 590 // NOTE: bootstrap_check_in always yields +1 receive-right 591 ret = bootstrap_check_in(bs, (char *)utfname, &mp); /* If we're started by launchd or the old mach_init */ 592 593 if (ret == KERN_SUCCESS) { 594 ret = mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND); 595 if (KERN_SUCCESS == ret) { 596 CFMachPortContext ctx = {0, ms, NULL, NULL, NULL}; 597 native = CFMachPortCreateWithPort(allocator, mp, __CFMessagePortDummyCallback, &ctx, NULL); 598 // at this point we have +1 SEND, +1 RECV, so we record that fact 599 __CFMessagePortSetExtraMachRef(ms); 600 } else { 601 __CFMessagePortUnlock(ms); 602 // balance the +1 receive-right we got from bootstrap_check_in 603 mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); 604 605 // the insert failed, so we don't need to decrement send right here 606 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 607 CFRelease(name); 608 return false; 609 } 610 } 611 612 if (!native) { 613 CFMachPortContext ctx = {0, ms, NULL, NULL, NULL}; 614 native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); 615 if (!native) { 616 __CFMessagePortUnlock(ms); 617 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 618 CFRelease(name); 619 return false; 620 } 621 mp = CFMachPortGetPort(native); 622 } 623 CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); 624 ms->_port = native; 625 if (NULL != oldPort && oldPort != native) { 626 if (previousNameHadExtraRef) { 627 // this code is known to be incorrect when ms->_dispatchSource is non-null, we prevent this above, but just to be sure we're not about to do something bad we assert 628 assert(ms->_dispatchSource == NULL); 629 630 // this is one of the reasons we are deprecating this API 631 mach_port_t const oldmp = CFMachPortGetPort(oldPort); 632 mach_port_mod_refs(mach_task_self(), oldmp, MACH_PORT_RIGHT_RECEIVE, -1); 633 mach_port_deallocate(mach_task_self(), oldmp); 634 } 635 CFMachPortInvalidate(oldPort); 636 CFRelease(oldPort); 637 } 638 os_unfair_lock_lock(&__CFAllMessagePortsLock); 639 // This relocking without checking to see if something else has grabbed 640 // that name in the cache is rather suspect, but what would that even 641 // mean has happened? We'd expect the bootstrap_* calls above to have 642 // failed for this one and not gotten this far, or failed for all of the 643 // other simultaneous attempts to get the name (and having succeeded for 644 // this one, gotten here). So we're not going to try very hard here 645 // with the thread-safety. 646 if (NULL == __CFAllLocalMessagePorts) { 647 __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); 648 } 649 if (NULL != ms->_name) { 650 CFDictionaryRemoveValue(__CFAllLocalMessagePorts, ms->_name); 651 CFRelease(ms->_name); 652 } 653 ms->_name = name; // consumes the +1 from sanitize above 654 CFDictionaryAddValue(__CFAllLocalMessagePorts, name, ms); 655 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 656 } 657 else if (name) { 658 // if setting the same name on the message port, then avoid leak 659 CFRelease(name); 660 } 661 __CFMessagePortUnlock(ms); 662 CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); 663 return true; 664 } 665 666 void CFMessagePortGetContext(CFMessagePortRef ms, CFMessagePortContext *context) { 667 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 668 //#warning CF: assert that this is a local port 669 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); 670 memmove(context, &ms->_context, sizeof(CFMessagePortContext)); 671 } 672 673 void CFMessagePortInvalidate(CFMessagePortRef ms) { 674 CF_ASSERT_TYPE_OR_NULL(_kCFRuntimeIDCFMessagePort, ms); 675 if (ms == NULL) { 676 return; 677 } 678 if (!__CFMessagePortIsDeallocing(ms)) { 679 CFRetain(ms); 680 } 681 __CFMessagePortLock(ms); 682 if (__CFMessagePortIsValid(ms)) { 683 if (ms->_dispatchSource) { 684 dispatch_source_cancel(ms->_dispatchSource); 685 ms->_dispatchSource = NULL; 686 ms->_dispatchQ = NULL; 687 } 688 689 CFMessagePortInvalidationCallBack callout = ms->_icallout; 690 CFRunLoopSourceRef source = ms->_source; 691 CFMachPortRef replyPort = ms->_replyPort; 692 CFMachPortRef port = ms->_port; 693 CFStringRef name = ms->_name; 694 void *info = NULL; 695 696 __CFMessagePortUnsetValid(ms); 697 if (!__CFMessagePortIsRemote(ms)) { 698 info = ms->_context.info; 699 ms->_context.info = NULL; 700 } 701 ms->_source = NULL; 702 ms->_replyPort = NULL; 703 ms->_port = NULL; 704 __CFMessagePortUnlock(ms); 705 706 os_unfair_lock_lock(&__CFAllMessagePortsLock); 707 if (0 == ms->_perPID && NULL != name && NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { 708 CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts, name); 709 } 710 os_unfair_lock_unlock(&__CFAllMessagePortsLock); 711 if (NULL != callout) { 712 callout(ms, info); 713 } 714 if (!__CFMessagePortIsRemote(ms) && NULL != ms->_context.release) { 715 ms->_context.release(info); 716 } 717 if (NULL != source) { 718 CFRunLoopSourceInvalidate(source); 719 CFRelease(source); 720 } 721 if (NULL != replyPort) { 722 CFMachPortInvalidate(replyPort); 723 CFRelease(replyPort); 724 } 725 726 if (NULL != port) { 727 mach_port_t const mp = CFMachPortGetPort(port); 728 if (__CFMessagePortIsRemote(ms)) { 729 _cfmp_record_deallocation(_CFMPLifetimeClientCFMessagePort, mp, true /*doSend*/, false /*doReceive*/); 730 } 731 // We already know we're going invalid, don't need this callback 732 // anymore; plus, this solves a reentrancy deadlock; also, this 733 // must be done before the deallocate of the Mach port, to 734 // avoid a race between the notification message which could be 735 // handled in another thread, and this NULL'ing out. 736 CFMachPortSetInvalidationCallBack(port, NULL); 737 if (__CFMessagePortExtraMachRef(ms)) { 738 _cfmp_record_deallocation(_CFMPLifetimeClientCFMessagePort, mp, true /*doSend*/, true /*doReceive*/); 739 } 740 CFMachPortInvalidate(port); 741 CFRelease(port); 742 } 743 } else { 744 __CFMessagePortUnlock(ms); 745 } 746 if (!__CFMessagePortIsDeallocing(ms)) { 747 CFRelease(ms); 748 } 749 } 750 751 Boolean CFMessagePortIsValid(CFMessagePortRef ms) { 752 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 753 if (!__CFMessagePortIsValid(ms)) return false; 754 CFRetain(ms); 755 if (NULL != ms->_port && !CFMachPortIsValid(ms->_port)) { 756 CFMessagePortInvalidate(ms); 757 CFRelease(ms); 758 return false; 759 } 760 if (NULL != ms->_replyPort && !CFMachPortIsValid(ms->_replyPort)) { 761 CFMessagePortInvalidate(ms); 762 CFRelease(ms); 763 return false; 764 } 765 CFRelease(ms); 766 return true; 767 } 768 769 CFMessagePortInvalidationCallBack CFMessagePortGetInvalidationCallBack(CFMessagePortRef ms) { 770 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 771 return ms->_icallout; 772 } 773 774 void CFMessagePortSetInvalidationCallBack(CFMessagePortRef ms, CFMessagePortInvalidationCallBack callout) { 775 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 776 if (!__CFMessagePortIsValid(ms) && NULL != callout) { 777 callout(ms, ms->_context.info); 778 } else { 779 ms->_icallout = callout; 780 } 781 } 782 783 static void __CFMessagePortReplyCallBack(CFMachPortRef port, void *msg, CFIndex size, void *info) { 784 CFMessagePortRef ms = info; 785 mach_msg_base_t *msgp = msg; 786 mach_msg_base_t *replymsg; 787 __CFMessagePortLock(ms); 788 if (!__CFMessagePortIsValid(ms)) { 789 __CFMessagePortUnlock(ms); 790 return; 791 } 792 793 int32_t byteslen = 0; 794 795 Boolean wayTooSmall = size < sizeof(mach_msg_header_t) || size < MSGP_SIZE(msgp) || msgp->header.msgh_size < MSGP_SIZE(msgp); 796 Boolean invalidMagic = false; 797 Boolean invalidComplex = false; 798 Boolean wayTooBig = false; 799 if (!wayTooSmall) { 800 invalidMagic = ((MSGP_INFO(msgp, magic) != MAGIC) && (CFSwapInt32(MSGP_INFO(msgp, magic)) != MAGIC)); 801 invalidComplex = (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && ((1 != msgp->body.msgh_descriptor_count) || MSGP_GET(msgp, ool).type != MACH_MSG_OOL_DESCRIPTOR); 802 wayTooBig = ((int32_t)MSGP_SIZE(msgp) + __CFMessagePortMaxInlineBytes) < msgp->header.msgh_size; // also less than a 32-bit signed int can hold 803 } 804 805 Boolean wrongSize = false; 806 if (!(invalidComplex || wayTooBig || wayTooSmall)) { 807 byteslen = CFSwapInt32LittleToHost(MSGP_INFO(msgp, byteslen)); 808 wrongSize = (byteslen < -1) || (__CFMessagePortMaxDataSize < byteslen); 809 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 810 wrongSize = wrongSize || (MSGP_GET(msgp, ool).size != byteslen); 811 } else { 812 wrongSize = wrongSize || ((int32_t)msgp->header.msgh_size - (int32_t)MSGP_SIZE(msgp) < byteslen); 813 } 814 } 815 Boolean invalidMsgID = wayTooSmall ? false : ((0 <= MSGP_INFO(msgp, convid)) && (MSGP_INFO(msgp, convid) <= INT32_MAX)); // conversation id 816 if (invalidMagic || invalidComplex || wayTooBig || wayTooSmall || wrongSize || invalidMsgID) { 817 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort: dropping corrupt reply Mach message (0b%d%d%d%d%d%d)"), invalidMagic, invalidComplex, wayTooBig, wayTooSmall, wrongSize, invalidMsgID); 818 mach_msg_destroy((mach_msg_header_t *)msgp); 819 __CFMessagePortUnlock(ms); 820 return; 821 } 822 823 if (CFDictionaryContainsKey(ms->_replies, (void *)(uintptr_t)MSGP_INFO(msgp, convid))) { 824 CFTypeRef reply = NULL; 825 replymsg = (mach_msg_base_t *)msg; 826 if (!(replymsg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { 827 uintptr_t msgp_extent = (uintptr_t)((uint8_t *)msgp + msgp->header.msgh_size); 828 uintptr_t data_extent = (uintptr_t)((uint8_t *)&(MSGP_INFO(replymsg, bytes)) + byteslen); 829 if (byteslen < 0) byteslen = 0; // from here on, treat negative same as zero -- this is historical behavior: a NULL return from the callback on the other side results in empty data to the original requestor 830 if (0 <= byteslen && data_extent <= msgp_extent) { 831 reply = CFDataCreate(kCFAllocatorSystemDefault, MSGP_INFO(replymsg, bytes), byteslen); 832 } else { 833 reply = CFRetain(kCFBooleanFalse); // means NULL data 834 } 835 } else { 836 //#warning CF: should create a no-copy data here that has a custom VM-freeing allocator, and not vm_dealloc here 837 reply = CFDataCreate(kCFAllocatorSystemDefault, MSGP_GET(replymsg, ool).address, MSGP_GET(replymsg, ool).size); 838 vm_deallocate(mach_task_self(), (vm_address_t)MSGP_GET(replymsg, ool).address, MSGP_GET(replymsg, ool).size); 839 } 840 CFDictionarySetValue(ms->_replies, (void *)(uintptr_t)MSGP_INFO(msgp, convid), reply); 841 CFRelease(reply); 842 } else { /* discard message */ 843 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 844 vm_deallocate(mach_task_self(), (vm_address_t)MSGP_GET(msgp, ool).address, MSGP_GET(msgp, ool).size); 845 } 846 } 847 __CFMessagePortUnlock(ms); 848 } 849 850 SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef data, CFTimeInterval sendTimeout, CFTimeInterval rcvTimeout, CFStringRef replyMode, CFDataRef *returnDatap) { 851 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, remote); 852 mach_msg_base_t *sendmsg; 853 CFRunLoopRef currentRL = CFRunLoopGetCurrent(); 854 CFRunLoopSourceRef source = NULL; 855 CFTypeRef reply = NULL; 856 uint64_t termTSR; 857 uint32_t sendOpts = 0, sendTimeOut = 0; 858 int32_t desiredReply; 859 Boolean didRegister = false; 860 kern_return_t ret; 861 862 //#warning CF: This should be an assert 863 // if (!__CFMessagePortIsRemote(remote)) return -999; 864 if (data && __CFMessagePortMaxDataSize < CFDataGetLength(data)) { 865 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSendRequest: CFMessagePort cannot send more than %lu bytes of data"), __CFMessagePortMaxDataSize); 866 return kCFMessagePortTransportError; 867 } 868 __CFMessagePortLock(remote); 869 if (!__CFMessagePortIsValid(remote)) { 870 __CFMessagePortUnlock(remote); 871 return kCFMessagePortIsInvalid; 872 } 873 CFRetain(remote); // retain during run loop to avoid invalidation causing freeing 874 if (NULL == remote->_replyPort) { 875 CFMachPortContext context; 876 context.version = 0; 877 context.info = remote; 878 context.retain = (const void *(*)(const void *))CFRetain; 879 context.release = (void (*)(const void *))CFRelease; 880 context.copyDescription = (CFStringRef (*)(const void *))__CFMessagePortCopyDescription; 881 remote->_replyPort = CFMachPortCreate(CFGetAllocator(remote), __CFMessagePortReplyCallBack, &context, NULL); 882 } 883 remote->_convCounter++; 884 desiredReply = -remote->_convCounter; 885 sendmsg = __CFMessagePortCreateMessage(false, CFMachPortGetPort(remote->_port), (replyMode != NULL ? CFMachPortGetPort(remote->_replyPort) : MACH_PORT_NULL), -desiredReply, msgid, (data ? CFDataGetBytePtr(data) : NULL), (data ? CFDataGetLength(data) : -1)); 886 if (!sendmsg) { 887 __CFMessagePortUnlock(remote); 888 CFRelease(remote); 889 return kCFMessagePortTransportError; 890 } 891 if (replyMode != NULL) { 892 CFDictionarySetValue(remote->_replies, (void *)(uintptr_t)desiredReply, kCFNull); 893 source = CFMachPortCreateRunLoopSource(CFGetAllocator(remote), remote->_replyPort, -100); 894 didRegister = !CFRunLoopContainsSource(currentRL, source, replyMode); 895 if (didRegister) { 896 CFRunLoopAddSource(currentRL, source, replyMode); 897 } 898 } 899 if (sendTimeout < 10.0*86400) { 900 // anything more than 10 days is no timeout! 901 sendOpts = MACH_SEND_TIMEOUT; 902 sendTimeout *= 1000.0; 903 if (sendTimeout < 1.0) sendTimeout = 0.0; 904 sendTimeOut = (uint32_t)floor(sendTimeout); 905 } 906 __CFMessagePortUnlock(remote); 907 ret = mach_msg((mach_msg_header_t *)sendmsg, MACH_SEND_MSG|sendOpts, sendmsg->header.msgh_size, 0, MACH_PORT_NULL, sendTimeOut, MACH_PORT_NULL); 908 __CFMessagePortLock(remote); 909 if (KERN_SUCCESS != ret) { 910 // need to deallocate the send-once right that might have been created 911 if (replyMode != NULL && 912 (ret == MACH_SEND_INVALID_DEST || ret == MACH_SEND_INTERRUPTED || ret == MACH_SEND_TIMED_OUT) // [55207069, 39359253] it is only valid to clean cleaup the local port for these two return values; to do otherwise is unsafe/undefined-behavior 913 ) { 914 mach_port_t port = ((mach_msg_header_t *)sendmsg)->msgh_local_port; 915 if (MACH_PORT_VALID(port)) { 916 if (MACH_MSGH_BITS_LOCAL(((mach_msg_header_t *)sendmsg)->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) { 917 /* destroy the send-once right */ 918 (void) mach_port_deallocate(mach_task_self(), port); 919 ((mach_msg_header_t *)sendmsg)->msgh_local_port = MACH_PORT_NULL; 920 } 921 } 922 } 923 if (didRegister) { 924 CFRunLoopRemoveSource(currentRL, source, replyMode); 925 } 926 if (source) CFRelease(source); 927 __CFMessagePortUnlock(remote); 928 CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg); 929 CFRelease(remote); 930 return (MACH_SEND_TIMED_OUT == ret) ? kCFMessagePortSendTimeout : kCFMessagePortTransportError; 931 } 932 __CFMessagePortUnlock(remote); 933 CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg); 934 if (replyMode == NULL) { 935 CFRelease(remote); 936 return kCFMessagePortSuccess; 937 } 938 _CFMachPortInstallNotifyPort(currentRL, replyMode); 939 termTSR = mach_absolute_time() + __CFTimeIntervalToTSR(rcvTimeout); 940 for (;;) { 941 CFRunLoopRunInMode(replyMode, __CFTimeIntervalUntilTSR(termTSR), true); 942 // warning: what, if anything, should be done if remote is now invalid? 943 reply = CFDictionaryGetValue(remote->_replies, (void *)(uintptr_t)desiredReply); 944 if (!(NULL == reply || kCFNull == reply) || termTSR < mach_absolute_time()) { 945 break; 946 } 947 if (!CFMessagePortIsValid(remote)) { 948 // no reason that reply port alone should go invalid so we don't check for that 949 break; 950 } 951 } 952 // Should we uninstall the notify port? A complex question... 953 if (didRegister) { 954 CFRunLoopRemoveSource(currentRL, source, replyMode); 955 } 956 if (source) CFRelease(source); 957 // kCFNull is the placeholder for a reply mode 958 if (NULL == reply || kCFNull == reply) { 959 CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply); 960 CFRelease(remote); 961 return CFMessagePortIsValid(remote) ? kCFMessagePortReceiveTimeout : kCFMessagePortBecameInvalidError; 962 } 963 if (NULL != returnDatap) { 964 // kCFBooleanFalse is the placeholder for a null data 965 *returnDatap = (kCFBooleanFalse == reply) ? NULL : CFRetain((CFDataRef)reply); 966 } 967 CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply); 968 CFRelease(remote); 969 return kCFMessagePortSuccess; 970 } 971 972 static mach_port_t __CFMessagePortGetPort(void *info) { 973 CFMessagePortRef ms = info; 974 if (!ms->_port && __CFMessagePortIsValid(ms)) CFLog(kCFLogLevelWarning, CFSTR("*** Warning: A local CFMessagePort (%p) is being put in a run loop or dispatch queue, but it has not been named yet, so this will be a no-op and no messages are going to be received, even if named later."), info); 975 return ms->_port ? CFMachPortGetPort(ms->_port) : MACH_PORT_NULL; 976 } 977 978 979 static void *__CFMessagePortPerform(void *msg, CFIndex size, CFAllocatorRef allocator, void *info) { 980 CFMessagePortRef ms = info; 981 mach_msg_base_t *msgp = msg; 982 mach_msg_base_t *replymsg = NULL; 983 void *context_info; 984 void (*context_release)(const void *); 985 CFDataRef returnData, data = NULL; 986 void *return_bytes = NULL; 987 CFIndex return_len = -1; 988 int32_t msgid; 989 990 __CFMessagePortLock(ms); 991 if (!__CFMessagePortIsValid(ms)) { 992 __CFMessagePortUnlock(ms); 993 return NULL; 994 } 995 if (NULL != ms->_context.retain) { 996 context_info = (void *)ms->_context.retain(ms->_context.info); 997 context_release = ms->_context.release; 998 } else { 999 context_info = ms->_context.info; 1000 context_release = NULL; 1001 } 1002 __CFMessagePortUnlock(ms); 1003 1004 1005 int32_t byteslen = 0; 1006 1007 Boolean wayTooSmall = size < sizeof(mach_msg_header_t) || size < MSGP_SIZE(msgp) || msgp->header.msgh_size < MSGP_SIZE(msgp); 1008 Boolean invalidMagic = false; 1009 Boolean invalidComplex = false; 1010 Boolean wayTooBig = false; 1011 if (!wayTooSmall) { 1012 invalidMagic = ((MSGP_INFO(msgp, magic) != MAGIC) && (CFSwapInt32(MSGP_INFO(msgp, magic)) != MAGIC)); 1013 invalidComplex = (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (1 != msgp->body.msgh_descriptor_count); 1014 wayTooBig = ((int32_t)MSGP_SIZE(msgp) + __CFMessagePortMaxInlineBytes) < msgp->header.msgh_size; // also less than a 32-bit signed int can hold 1015 } 1016 Boolean wrongSize = false; 1017 if (!(invalidComplex || wayTooBig || wayTooSmall)) { 1018 byteslen = CFSwapInt32LittleToHost(MSGP_INFO(msgp, byteslen)); 1019 wrongSize = (byteslen < -1) || (__CFMessagePortMaxDataSize < byteslen); 1020 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 1021 wrongSize = wrongSize || (MSGP_GET(msgp, ool).size != byteslen); 1022 } else { 1023 wrongSize = wrongSize || ((int32_t)msgp->header.msgh_size - (int32_t)MSGP_SIZE(msgp) < byteslen); 1024 } 1025 } 1026 Boolean invalidMsgID = wayTooSmall ? false : ((MSGP_INFO(msgp, convid) <= 0) || (INT32_MAX < MSGP_INFO(msgp, convid))); // conversation id 1027 if (invalidMagic || invalidComplex || wayTooBig || wayTooSmall || wrongSize || invalidMsgID) { 1028 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort: dropping corrupt request Mach message (0b%d%d%d%d%d%d)"), invalidMagic, invalidComplex, wayTooBig, wayTooSmall, wrongSize, invalidMsgID); 1029 mach_msg_destroy((mach_msg_header_t *)msgp); 1030 return NULL; 1031 } 1032 1033 if (byteslen < 0) byteslen = 0; // from here on, treat negative same as zero 1034 1035 /* Create no-copy, no-free-bytes wrapper CFData */ 1036 if (!(msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX)) { 1037 uintptr_t msgp_extent = (uintptr_t)((uint8_t *)msgp + msgp->header.msgh_size); 1038 uintptr_t data_extent = (uintptr_t)((uint8_t *)&(MSGP_INFO(msgp, bytes)) + byteslen); 1039 msgid = CFSwapInt32LittleToHost(MSGP_INFO(msgp, msgid)); 1040 if (0 <= byteslen && data_extent <= msgp_extent) { 1041 data = CFDataCreateWithBytesNoCopy(allocator, MSGP_INFO(msgp, bytes), byteslen, kCFAllocatorNull); 1042 } 1043 } else { 1044 msgid = CFSwapInt32LittleToHost(MSGP_INFO(msgp, msgid)); 1045 data = CFDataCreateWithBytesNoCopy(allocator, MSGP_GET(msgp, ool).address, MSGP_GET(msgp, ool).size, kCFAllocatorNull); 1046 } 1047 if (ms->_callout) { 1048 returnData = ms->_callout(ms, msgid, data, context_info); 1049 } else { 1050 mach_msg_trailer_t *trailer = (mach_msg_trailer_t *)(((uintptr_t)&(msgp->header) + msgp->header.msgh_size + sizeof(natural_t) - 1) & ~(sizeof(natural_t) - 1)); 1051 returnData = ms->_calloutEx(ms, msgid, data, context_info, trailer, 0); 1052 } 1053 /* Now, returnData could be (1) NULL, (2) an ordinary data < MAX_INLINE, 1054 (3) ordinary data >= MAX_INLINE, (4) a no-copy data < MAX_INLINE, 1055 (5) a no-copy data >= MAX_INLINE. In cases (2) and (4), we send the return 1056 bytes inline in the Mach message, so can release the returnData object 1057 here. In cases (3) and (5), we'll send the data out-of-line, we need to 1058 create a copy of the memory, which we'll have the kernel autodeallocate 1059 for us on send. In case (4) also, the bytes in the return data may be part 1060 of the bytes in "data" that we sent into the callout, so if the incoming 1061 data was received out of line, we wouldn't be able to clean up the out-of-line 1062 wad until the message was sent either, if we didn't make the copy. */ 1063 if (NULL != returnData) { 1064 return_len = CFDataGetLength(returnData); 1065 if (__CFMessagePortMaxDataSize < return_len) { 1066 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort reply: CFMessagePort cannot send more than %lu bytes of data"), __CFMessagePortMaxDataSize); 1067 return_len = 0; 1068 CFRelease(returnData); 1069 returnData = NULL; 1070 } 1071 if (returnData && return_len < __CFMessagePortMaxInlineBytes) { 1072 return_bytes = (void *)CFDataGetBytePtr(returnData); 1073 } else if (returnData) { 1074 return_bytes = NULL; 1075 kern_return_t ret = vm_allocate(mach_task_self(), (vm_address_t *)&return_bytes, return_len, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG)); 1076 if (ret == KERN_SUCCESS) { 1077 /* vm_copy would only be a win here if the source address 1078 is page aligned; it is a lose in all other cases, since 1079 the kernel will just do the memmove for us (but not in 1080 as simple a way). */ 1081 memmove(return_bytes, CFDataGetBytePtr(returnData), return_len); 1082 } else { 1083 return_len = 0; 1084 } 1085 } 1086 } 1087 replymsg = __CFMessagePortCreateMessage(true, msgp->header.msgh_remote_port, MACH_PORT_NULL, -1 * (int32_t)MSGP_INFO(msgp, convid), msgid, return_bytes, return_len); 1088 if (replymsg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 1089 MSGP_GET(replymsg, ool).deallocate = true; 1090 } 1091 if (data) CFRelease(data); 1092 if (msgp->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { 1093 vm_deallocate(mach_task_self(), (vm_address_t)MSGP_GET(msgp, ool).address, MSGP_GET(msgp, ool).size); 1094 } 1095 if (returnData) CFRelease(returnData); 1096 if (context_release) { 1097 context_release(context_info); 1098 } 1099 return replymsg; 1100 } 1101 1102 CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef ms, CFIndex order) { 1103 CF_ASSERT_TYPE_OR_NULL(_kCFRuntimeIDCFMessagePort, ms); 1104 CFRunLoopSourceRef result = NULL; 1105 if (!CFMessagePortIsValid(ms)) return NULL; 1106 if (__CFMessagePortIsRemote(ms)) return NULL; 1107 __CFMessagePortLock(ms); 1108 if (NULL != ms->_source && !CFRunLoopSourceIsValid(ms->_source)) { 1109 CFRelease(ms->_source); 1110 ms->_source = NULL; 1111 } 1112 if (NULL == ms->_source && NULL == ms->_dispatchSource && __CFMessagePortIsValid(ms)) { 1113 CFRunLoopSourceContext1 context; 1114 context.version = 1; 1115 context.info = (void *)ms; 1116 context.retain = (const void *(*)(const void *))CFRetain; 1117 context.release = (void (*)(const void *))CFRelease; 1118 context.copyDescription = (CFStringRef (*)(const void *))__CFMessagePortCopyDescription; 1119 context.equal = NULL; 1120 context.hash = NULL; 1121 context.getPort = __CFMessagePortGetPort; 1122 context.perform = __CFMessagePortPerform; 1123 ms->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context); 1124 } 1125 if (NULL != ms->_source) { 1126 result = (CFRunLoopSourceRef)CFRetain(ms->_source); 1127 } 1128 __CFMessagePortUnlock(ms); 1129 return result; 1130 } 1131 1132 void CFMessagePortSetDispatchQueue(CFMessagePortRef ms, dispatch_queue_t queue) { 1133 CF_ASSERT_TYPE(_kCFRuntimeIDCFMessagePort, ms); 1134 __CFMessagePortLock(ms); 1135 if (!__CFMessagePortIsValid(ms)) { 1136 __CFMessagePortUnlock(ms); 1137 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): CFMessagePort is invalid")); 1138 return; 1139 } 1140 if (__CFMessagePortIsRemote(ms)) { 1141 __CFMessagePortUnlock(ms); 1142 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): CFMessagePort is not a local port, queue cannot be set")); 1143 return; 1144 } 1145 if (NULL != ms->_source) { 1146 __CFMessagePortUnlock(ms); 1147 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): CFMessagePort already has a CFRunLoopSourceRef, queue cannot be set")); 1148 return; 1149 } 1150 1151 if (ms->_dispatchSource) { 1152 dispatch_source_cancel(ms->_dispatchSource); 1153 ms->_dispatchSource = NULL; 1154 ms->_dispatchQ = NULL; 1155 } 1156 1157 if (queue) { 1158 mach_port_t port = __CFMessagePortGetPort(ms); 1159 if (MACH_PORT_NULL != port) { 1160 static dispatch_queue_t mportQueue = NULL; 1161 static dispatch_once_t once; 1162 dispatch_once(&once, ^{ 1163 dispatch_queue_attr_t dqattr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, qos_class_main(), 0); 1164 mportQueue = dispatch_queue_create("com.apple.CFMessagePort", dqattr); 1165 }); 1166 1167 _cfmp_record_intent_to_invalidate(_CFMPLifetimeClientCFMessagePort, port); 1168 dispatch_source_t theSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, port, 0, mportQueue); 1169 dispatch_source_set_cancel_handler(theSource, ^{ 1170 dispatch_release(queue); 1171 dispatch_release(theSource); 1172 _cfmp_source_invalidated(_CFMPLifetimeClientCFMessagePort, port); 1173 }); 1174 dispatch_source_set_event_handler(theSource, ^{ 1175 CFRetain(ms); 1176 mach_msg_header_t *msg = (mach_msg_header_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2048, 0); 1177 msg->msgh_size = 2048; 1178 1179 for (;;) { 1180 msg->msgh_bits = 0; 1181 msg->msgh_local_port = port; 1182 msg->msgh_remote_port = MACH_PORT_NULL; 1183 msg->msgh_id = 0; 1184 1185 kern_return_t ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, port, 0, MACH_PORT_NULL); 1186 if (MACH_MSG_SUCCESS == ret) break; 1187 if (MACH_RCV_TOO_LARGE != ret) HALT; 1188 1189 uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); 1190 msg = __CFSafelyReallocateWithAllocator(kCFAllocatorSystemDefault, msg, newSize, 0, NULL); 1191 msg->msgh_size = newSize; 1192 } 1193 1194 dispatch_async(queue, ^{ 1195 mach_msg_header_t *reply = __CFMessagePortPerform(msg, msg->msgh_size, kCFAllocatorSystemDefault, ms); 1196 if (NULL != reply) { 1197 kern_return_t const ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); 1198 1199 __CFMachMessageCheckForAndDestroyUnsentMessage(ret, reply); 1200 1201 CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); 1202 } 1203 CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); 1204 CFRelease(ms); 1205 }); 1206 }); 1207 ms->_dispatchSource = theSource; 1208 } 1209 if (ms->_dispatchSource) { 1210 dispatch_retain(queue); 1211 ms->_dispatchQ = queue; 1212 dispatch_resume(ms->_dispatchSource); 1213 } else { 1214 CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePortSetDispatchQueue(): dispatch source could not be created")); 1215 } 1216 } 1217 __CFMessagePortUnlock(ms); 1218 }