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