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