1 /* 2 * Copyright (c) 2000,2008-2009 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 /* 29 * Copyright (c) 1997 Apple Inc. 30 * 31 */ 32 #include <libkern/c++/OSMetaClass.h> 33 #include <libkern/c++/OSKext.h> 34 #include <libkern/c++/OSLib.h> 35 #include <libkern/c++/OSSymbol.h> 36 #include <IOKit/IOKitDebug.h> 37 38 #include <sys/cdefs.h> 39 40 __BEGIN_DECLS 41 42 #include <string.h> 43 #include <mach/mach_types.h> 44 #include <libkern/kernel_mach_header.h> 45 #include <stdarg.h> 46 47 #if PRAGMA_MARK 48 #pragma mark Constants &c. 49 #endif /* PRAGMA_MARK */ 50 OSKextLogSpec kOSRuntimeLogSpec = 51 kOSKextLogErrorLevel | 52 kOSKextLogLoadFlag | 53 kOSKextLogKextBookkeepingFlag; 54 55 #if PRAGMA_MARK 56 #pragma mark Logging Bootstrap 57 #endif /* PRAGMA_MARK */ 58 /********************************************************************* 59 * kern_os Logging Bootstrap 60 * 61 * We can't call in to OSKext until the kernel's C++ environment is up 62 * and running, so let's mask those references with a check variable. 63 * We print unconditionally if C++ isn't up, but if that's the case 64 * we've generally hit a serious error in kernel init! 65 *********************************************************************/ 66 static bool gKernelCPPInitialized = false; 67 68 #define OSRuntimeLog(kext, flags, format, args...) \ 69 do { \ 70 if (gKernelCPPInitialized) { \ 71 OSKextLog((kext), (flags), (format), ## args); \ 72 } else { \ 73 printf((format), ## args); \ 74 } \ 75 } while (0) 76 77 #if PRAGMA_MARK 78 #pragma mark kern_os Allocator Package 79 #endif /* PRAGMA_MARK */ 80 /********************************************************************* 81 * kern_os Allocator Package 82 *********************************************************************/ 83 84 /********************************************************************* 85 *********************************************************************/ 86 #if OSALLOCDEBUG 87 extern int debug_iomalloc_size; 88 #endif 89 90 /********************************************************************* 91 *********************************************************************/ 92 void * 93 kern_os_malloc(size_t size) 94 { 95 void *mem; 96 if (size == 0) { 97 return (0); 98 } 99 100 mem = kallocp_tag_bt((vm_size_t *)&size, VM_KERN_MEMORY_LIBKERN); 101 if (!mem) { 102 return (0); 103 } 104 105 #if OSALLOCDEBUG 106 OSAddAtomic(size, &debug_iomalloc_size); 107 #endif 108 109 bzero(mem, size); 110 111 return mem; 112 } 113 114 /********************************************************************* 115 *********************************************************************/ 116 void 117 kern_os_free(void * addr) 118 { 119 size_t size; 120 size = kalloc_size(addr); 121 #if OSALLOCDEBUG 122 OSAddAtomic(-size, &debug_iomalloc_size); 123 #endif 124 125 kfree_addr(addr); 126 } 127 128 /********************************************************************* 129 *********************************************************************/ 130 void * 131 kern_os_realloc( 132 void * addr, 133 size_t nsize) 134 { 135 void *nmem; 136 size_t osize; 137 138 if (!addr) { 139 return (kern_os_malloc(nsize)); 140 } 141 142 osize = kalloc_size(addr); 143 if (nsize == osize) { 144 return (addr); 145 } 146 147 if (nsize == 0) { 148 kfree_addr(addr); 149 return (0); 150 } 151 152 nmem = kallocp_tag_bt((vm_size_t *)&nsize, VM_KERN_MEMORY_LIBKERN); 153 if (!nmem){ 154 kfree_addr(addr); 155 return (0); 156 } 157 158 #if OSALLOCDEBUG 159 OSAddAtomic((nsize - osize), &debug_iomalloc_size); 160 #endif 161 162 if (nsize > osize) { 163 (void)memset((char *)nmem + osize, 0, nsize - osize); 164 } 165 (void)memcpy(nmem, addr, (nsize > osize) ? osize : nsize); 166 kfree_addr(addr); 167 168 return (nmem); 169 } 170 171 #if PRAGMA_MARK 172 #pragma mark C++ Runtime Load/Unload 173 #endif /* PRAGMA_MARK */ 174 /********************************************************************* 175 * kern_os C++ Runtime Load/Unload 176 *********************************************************************/ 177 178 /********************************************************************* 179 *********************************************************************/ 180 #if __GNUC__ >= 3 181 void __cxa_pure_virtual( void ) { panic("%s", __FUNCTION__); } 182 #else 183 void __pure_virtual( void ) { panic("%s", __FUNCTION__); } 184 #endif 185 186 typedef void (*structor_t)(void); 187 188 /********************************************************************* 189 *********************************************************************/ 190 static boolean_t 191 sectionIsDestructor(kernel_section_t * section) 192 { 193 boolean_t result; 194 195 result = !strncmp(section->sectname, SECT_MODTERMFUNC, 196 sizeof(SECT_MODTERMFUNC) - 1); 197 #if !__LP64__ 198 result = result || !strncmp(section->sectname, SECT_DESTRUCTOR, 199 sizeof(SECT_DESTRUCTOR) - 1); 200 #endif 201 202 return result; 203 } 204 205 /********************************************************************* 206 *********************************************************************/ 207 static boolean_t 208 sectionIsConstructor(kernel_section_t * section) 209 { 210 boolean_t result; 211 212 result = !strncmp(section->sectname, SECT_MODINITFUNC, 213 sizeof(SECT_MODINITFUNC) - 1); 214 #if !__LP64__ 215 result = result || !strncmp(section->sectname, SECT_CONSTRUCTOR, 216 sizeof(SECT_CONSTRUCTOR) - 1); 217 #endif 218 219 return result; 220 } 221 222 223 /********************************************************************* 224 * OSRuntimeUnloadCPPForSegment() 225 * 226 * Given a pointer to a mach object segment, iterate the segment to 227 * obtain a destructor section for C++ objects, and call each of the 228 * destructors there. 229 *********************************************************************/ 230 231 void 232 OSRuntimeUnloadCPPForSegmentInKmod( 233 kernel_segment_command_t * segment, 234 kmod_info_t * kmodInfo) 235 { 236 237 kernel_section_t * section = NULL; // do not free 238 OSKext * theKext = NULL; // must release 239 240 if (gKernelCPPInitialized && kmodInfo) { 241 theKext = OSKext::lookupKextWithIdentifier(kmodInfo->name); 242 } 243 244 for (section = firstsect(segment); 245 section != 0; 246 section = nextsect(segment, section)) { 247 248 if (sectionIsDestructor(section)) { 249 structor_t * destructors = (structor_t *)section->addr; 250 251 if (destructors) { 252 int num_destructors = section->size / sizeof(structor_t); 253 int hit_null_destructor = 0; 254 255 for (int i = 0; i < num_destructors; i++) { 256 if (destructors[i]) { 257 (*destructors[i])(); 258 } else if (!hit_null_destructor) { 259 hit_null_destructor = 1; 260 OSRuntimeLog(theKext, kOSRuntimeLogSpec, 261 "Null destructor in kext %s segment %s!", 262 kmodInfo ? kmodInfo->name : "(unknown)", 263 section->segname); 264 } 265 } 266 } /* if (destructors) */ 267 } /* if (strncmp...) */ 268 } /* for (section...) */ 269 270 OSSafeReleaseNULL(theKext); 271 return; 272 } 273 274 void 275 OSRuntimeUnloadCPPForSegment(kernel_segment_command_t * segment) { 276 OSRuntimeUnloadCPPForSegmentInKmod(segment, NULL); 277 } 278 279 /********************************************************************* 280 *********************************************************************/ 281 void 282 OSRuntimeUnloadCPP( 283 kmod_info_t * kmodInfo, 284 void * data __unused) 285 { 286 if (kmodInfo && kmodInfo->address) { 287 288 kernel_segment_command_t * segment; 289 kernel_mach_header_t * header; 290 291 OSSymbol::checkForPageUnload((void *)kmodInfo->address, 292 (void *)(kmodInfo->address + kmodInfo->size)); 293 294 header = (kernel_mach_header_t *)kmodInfo->address; 295 segment = firstsegfromheader(header); 296 297 for (segment = firstsegfromheader(header); 298 segment != 0; 299 segment = nextsegfromheader(header, segment)) { 300 301 OSRuntimeUnloadCPPForSegmentInKmod(segment, kmodInfo); 302 } 303 } 304 305 return; 306 } 307 308 /********************************************************************* 309 *********************************************************************/ 310 kern_return_t 311 OSRuntimeFinalizeCPP( 312 kmod_info_t * kmodInfo, 313 void * data __unused) 314 { 315 kern_return_t result = KMOD_RETURN_FAILURE; 316 void * metaHandle = NULL; // do not free 317 OSKext * theKext = NULL; // must release 318 319 if (gKernelCPPInitialized) { 320 theKext = OSKext::lookupKextWithIdentifier(kmodInfo->name); 321 } 322 323 if (theKext && !theKext->isCPPInitialized()) { 324 result = KMOD_RETURN_SUCCESS; 325 goto finish; 326 } 327 328 /* OSKext checks for this condition now, but somebody might call 329 * this function directly (the symbol is exported....). 330 */ 331 if (OSMetaClass::modHasInstance(kmodInfo->name)) { 332 // xxx - Don't log under errors? this is more of an info thing 333 OSRuntimeLog(theKext, kOSRuntimeLogSpec, 334 "Can't tear down kext %s C++; classes have instances:", 335 kmodInfo->name); 336 OSKext::reportOSMetaClassInstances(kmodInfo->name, kOSRuntimeLogSpec); 337 result = kOSMetaClassHasInstances; 338 goto finish; 339 } 340 341 /* Tell the meta class system that we are starting to unload. 342 * metaHandle isn't actually needed on the finalize path, 343 * so we don't check it here, even though OSMetaClass::postModLoad() will 344 * return a failure (it only does actual work on the init path anyhow). 345 */ 346 metaHandle = OSMetaClass::preModLoad(kmodInfo->name); 347 OSRuntimeUnloadCPP(kmodInfo, 0); 348 (void)OSMetaClass::postModLoad(metaHandle); 349 350 if (theKext) { 351 theKext->setCPPInitialized(false); 352 } 353 result = KMOD_RETURN_SUCCESS; 354 finish: 355 OSSafeReleaseNULL(theKext); 356 return result; 357 } 358 359 // Functions used by the extenTools/kmod library project 360 361 /********************************************************************* 362 *********************************************************************/ 363 kern_return_t 364 OSRuntimeInitializeCPP( 365 kmod_info_t * kmodInfo, 366 void * data __unused) 367 { 368 kern_return_t result = KMOD_RETURN_FAILURE; 369 OSKext * theKext = NULL; // must release 370 kernel_mach_header_t * header = NULL; 371 void * metaHandle = NULL; // do not free 372 bool load_success = true; 373 kernel_segment_command_t * segment = NULL; // do not free 374 kernel_segment_command_t * failure_segment = NULL; // do not free 375 376 if (!kmodInfo || !kmodInfo->address) { 377 result = kOSKextReturnInvalidArgument; 378 goto finish; 379 } 380 381 if (gKernelCPPInitialized) { 382 theKext = OSKext::lookupKextWithIdentifier(kmodInfo->name); 383 } 384 385 if (theKext && theKext->isCPPInitialized()) { 386 result = KMOD_RETURN_SUCCESS; 387 goto finish; 388 } 389 390 header = (kernel_mach_header_t *)kmodInfo->address; 391 392 /* Tell the meta class system that we are starting the load 393 */ 394 metaHandle = OSMetaClass::preModLoad(kmodInfo->name); 395 assert(metaHandle); 396 if (!metaHandle) { 397 goto finish; 398 } 399 400 /* NO GOTO PAST HERE. */ 401 402 /* Scan the header for all constructor sections, in any 403 * segment, and invoke the constructors within those sections. 404 */ 405 for (segment = firstsegfromheader(header); 406 segment != NULL && load_success; 407 segment = nextsegfromheader(header, segment)) { 408 409 kernel_section_t * section; 410 411 /* Record the current segment in the event of a failure. 412 */ 413 failure_segment = segment; 414 415 for (section = firstsect(segment); 416 section != NULL; 417 section = nextsect(segment, section)) { 418 419 if (sectionIsConstructor(section)) { 420 structor_t * constructors = (structor_t *)section->addr; 421 422 if (constructors) { 423 int num_constructors = section->size / sizeof(structor_t); 424 int hit_null_constructor = 0; 425 426 for (int i = 0; 427 i < num_constructors && 428 OSMetaClass::checkModLoad(metaHandle); 429 i++) { 430 431 if (constructors[i]) { 432 (*constructors[i])(); 433 } else if (!hit_null_constructor) { 434 hit_null_constructor = 1; 435 OSRuntimeLog(theKext, kOSRuntimeLogSpec, 436 "Null constructor in kext %s segment %s!", 437 kmodInfo->name, section->segname); 438 } 439 } 440 load_success = OSMetaClass::checkModLoad(metaHandle); 441 442 break; 443 } /* if (constructors) */ 444 } /* if (strncmp...) */ 445 } /* for (section...) */ 446 } /* for (segment...) */ 447 448 /* We failed so call all of the destructors. We must do this before 449 * calling OSMetaClass::postModLoad() as the OSMetaClass destructors 450 * will alter state (in the metaHandle) used by that function. 451 */ 452 if (!load_success) { 453 454 /* Scan the header for all destructor sections, in any 455 * segment, and invoke the constructors within those sections. 456 */ 457 for (segment = firstsegfromheader(header); 458 segment != failure_segment && segment != 0; 459 segment = nextsegfromheader(header, segment)) { 460 461 OSRuntimeUnloadCPPForSegment(segment); 462 463 } /* for (segment...) */ 464 } 465 466 /* Now, regardless of success so far, do the post-init registration 467 * and cleanup. If we had to call the unloadCPP function, static 468 * destructors have removed classes from the stalled list so no 469 * metaclasses will actually be registered. 470 */ 471 result = OSMetaClass::postModLoad(metaHandle); 472 473 /* If we've otherwise been fine up to now, but OSMetaClass::postModLoad() 474 * fails (typically due to a duplicate class), tear down all the C++ 475 * stuff from the kext. This isn't necessary for libkern/OSMetaClass stuff, 476 * but may be necessary for other C++ code. We ignore the return value 477 * because it's only a fail when there are existing instances of libkern 478 * classes, and there had better not be any created on the C++ init path. 479 */ 480 if (load_success && result != KMOD_RETURN_SUCCESS) { 481 (void)OSRuntimeFinalizeCPP(kmodInfo, NULL); 482 } 483 484 if (theKext && load_success && result == KMOD_RETURN_SUCCESS) { 485 theKext->setCPPInitialized(true); 486 } 487 finish: 488 OSSafeReleaseNULL(theKext); 489 return result; 490 } 491 492 #if PRAGMA_MARK 493 #pragma mark Libkern Init 494 #endif /* PRAGMA_MARK */ 495 /********************************************************************* 496 * Libkern Init 497 *********************************************************************/ 498 499 /********************************************************************* 500 *********************************************************************/ 501 extern lck_grp_t * IOLockGroup; 502 extern kmod_info_t g_kernel_kmod_info; 503 504 void OSlibkernInit(void) 505 { 506 // This must be called before calling OSRuntimeInitializeCPP. 507 OSMetaClassBase::initialize(); 508 509 g_kernel_kmod_info.address = (vm_address_t) &_mh_execute_header; 510 if (kOSReturnSuccess != OSRuntimeInitializeCPP(&g_kernel_kmod_info, 0)) { 511 panic("OSRuntime: C++ runtime failed to initialize."); 512 } 513 514 gKernelCPPInitialized = true; 515 516 return; 517 } 518 519 __END_DECLS 520 521 #if PRAGMA_MARK 522 #pragma mark C++ Allocators & Deallocators 523 #endif /* PRAGMA_MARK */ 524 /********************************************************************* 525 * C++ Allocators & Deallocators 526 *********************************************************************/ 527 void * 528 operator new(size_t size) 529 #if __cplusplus >= 201103L 530 noexcept 531 #endif 532 { 533 void * result; 534 535 result = (void *) kern_os_malloc(size); 536 return result; 537 } 538 539 void 540 operator delete(void * addr) 541 #if __cplusplus >= 201103L 542 noexcept 543 #endif 544 { 545 kern_os_free(addr); 546 return; 547 } 548 549 void * 550 operator new[](unsigned long sz) 551 #if __cplusplus >= 201103L 552 noexcept 553 #endif 554 { 555 if (sz == 0) sz = 1; 556 return kern_os_malloc(sz); 557 } 558 559 void 560 operator delete[](void * ptr) 561 #if __cplusplus >= 201103L 562 noexcept 563 #endif 564 { 565 if (ptr) { 566 kern_os_free(ptr); 567 } 568 return; 569 } 570 571 /* PR-6481964 - The compiler is going to check for size overflows in calls to 572 * new[], and if there is an overflow, it will call __throw_length_error. 573 * This is an unrecoverable error by the C++ standard, so we must panic here. 574 * 575 * We have to put the function inside the std namespace because of how the 576 * compiler expects the name to be mangled. 577 */ 578 namespace std { 579 580 void 581 __throw_length_error(const char *msg __unused) 582 { 583 panic("Size of array created by new[] has overflowed"); 584 } 585 586 }; 587 588