chk_fail.c
1 /* 2 * Copyright (c) 2007-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_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. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 #include <os/assumes.h> 25 #include <stdint.h> 26 #include <TargetConditionals.h> 27 #include "crt_externs.h" 28 29 #ifndef PR_13085474_CHECK 30 #define PR_13085474_CHECK TARGET_OS_OSX 31 #endif 32 33 #if PR_13085474_CHECK 34 /* Some shipped applications fail this check and were tested against 35 * versions of these functions that supported overlapping buffers. 36 * 37 * We would rather let such applications run, using the old memmove 38 * implementation, than abort() because they can't use the new 39 * implementation. 40 */ 41 42 #include <libkern/OSAtomic.h> 43 #include <mach-o/dyld.h> 44 #include <mach-o/dyld_priv.h> 45 #if TARGET_OS_OSX 46 #define START_VERSION dyld_platform_version_macOS_10_9 47 #else 48 #error "This platform should not build with PR_13085474_CHECK=1" 49 #endif 50 #endif /* !PR_13085474_CHECK */ 51 52 /* For PR_13085474_CHECK set, we initialize __chk_assert_no_overlap to 53 * 1 initially and then reset it to 0 if the main image of the process 54 * was linked earlier than 10.9. 55 * 56 * If PR_13085474_CHECK is zero, then we never do any sdk version checking 57 * and always do overlap checks. 58 */ 59 __attribute__ ((visibility ("hidden"))) 60 uint32_t __chk_assert_no_overlap = 1; 61 62 #if PR_13085474_CHECK 63 static bool 64 __chk_assert_sdk_pre_start(const struct mach_header *mh) { 65 return (dyld_get_active_platform() == PLATFORM_MACOS && 66 !dyld_sdk_at_least(mh, START_VERSION)); 67 } 68 #endif 69 70 __attribute__ ((visibility ("hidden"))) 71 void __chk_init(void) { 72 #if PR_13085474_CHECK 73 if (__chk_assert_sdk_pre_start((const struct mach_header *) 74 _NSGetMachExecuteHeader())) { 75 __chk_assert_no_overlap = 0; 76 } 77 #endif 78 } 79 80 __attribute__ ((visibility ("hidden"))) 81 __attribute__ ((noreturn)) 82 void 83 __chk_fail_overflow (void) { 84 os_crash("detected buffer overflow"); 85 } 86 87 __attribute__ ((visibility ("hidden"))) 88 __attribute__ ((noreturn)) 89 void 90 __chk_fail_overlap (void) { 91 os_crash("detected source and destination buffer overlap"); 92 } 93 94 __attribute__ ((visibility ("hidden"))) 95 void 96 __chk_overlap (const void *_a, size_t an, const void *_b, size_t bn) { 97 uintptr_t a = (uintptr_t)_a; 98 uintptr_t b = (uintptr_t)_b; 99 100 if (__builtin_expect(an == 0 || bn == 0, 0)) { 101 return; 102 } else if (__builtin_expect(a == b, 0)) { 103 __chk_fail_overlap(); 104 } else if (a < b) { 105 if (__builtin_expect(a + an > b, 0)) 106 __chk_fail_overlap(); 107 } else { // b < a 108 if (__builtin_expect(b + bn > a, 0)) 109 __chk_fail_overlap(); 110 } 111 }