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