]> git.saurik.com Git - apple/libc.git/blob - secure/chk_fail.c
db859a6e6bdc9b5463ba36fc6a9c86b29602ea17
[apple/libc.git] / secure / 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 <syslog.h>
25 #include <sys/sysctl.h>
26 #include <sys/param.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <TargetConditionals.h>
30
31
32 #if !defined(PR_13085474_CHECK)
33 #define PR_13085474_CHECK 1
34
35 /* Some shipped applications fail this check and were tested against
36 * versions of these functions that supported overlapping buffers.
37 *
38 * We would rather let such applications run, using the old memmove
39 * implementation, than abort() because they can't use the new
40 * implementation.
41 */
42
43 #include <libkern/OSAtomic.h>
44 #include <mach-o/dyld.h>
45 #include <mach-o/dyld_priv.h>
46 #define DYLD_OS_VERSION(major, minor, tiny) ((((major) & 0xffff) << 16) | (((minor) & 0xff) << 8) | ((tiny) & 0xff))
47 #if TARGET_OS_IPHONE
48 #define START_VERSION DYLD_OS_VERSION(7,0,0)
49 #else
50 #define START_VERSION DYLD_OS_VERSION(10,9,0)
51 #endif
52 #endif /* !PR_13085474_CHECK */
53
54 /* For PR_13085474_CHECK set, we initialize __chk_assert_no_overlap to
55 * a value neither 0 or 1. We call _dyld_register_func_for_add_image()
56 * to register a callback, and use the non-one value of
57 * __chk_assert_no_overlap to skip sdk version checks (but we do
58 * perform overlap checks). To detect if the main program was built
59 * prior to START_VERSION, we call dyld_get_program_sdk_version(),
60 * which we do before setting up the callback (since we don't need it
61 * if the main program is older).
62 *
63 * After _dyld_register_func_for_add_image() returns, we set
64 * __chk_assert_no_overlap to 1, which enables the sdk version checking
65 * for subsequent loaded shared objects. If we then find an old version,
66 * we set __chk_assert_no_overlap to 0 to turn off overlap checking.
67 *
68 * If PR_13085474_CHECK is zero, then we never do any sdk version checking
69 * and always do overlap checks.
70 */
71 __attribute__ ((visibility ("hidden")))
72 uint32_t __chk_assert_no_overlap
73 #if PR_13085474_CHECK
74 = 42;
75 #else
76 = 1;
77 #endif
78
79 #if PR_13085474_CHECK
80 static void
81 __chk_assert_no_overlap_callback(const struct mach_header *mh, intptr_t vmaddr_slide __unused) {
82 if (__chk_assert_no_overlap != 1) return;
83 if (dyld_get_sdk_version(mh) < START_VERSION) OSAtomicAnd32(0U, &__chk_assert_no_overlap);
84 }
85 #endif
86
87 __attribute__ ((visibility ("hidden")))
88 void __chk_init(void) {
89 #if PR_13085474_CHECK
90 if (dyld_get_program_sdk_version() < START_VERSION) {
91 __chk_assert_no_overlap = 0;
92 } else {
93 _dyld_register_func_for_add_image(__chk_assert_no_overlap_callback);
94 __chk_assert_no_overlap = 1;
95 }
96 #endif
97 }
98
99 __attribute__ ((noreturn))
100 static void
101 __chk_fail (const char *message)
102 {
103 syslog(LOG_CRIT, "%s", message);
104 abort_report_np("%s", message);
105 }
106
107 __attribute__ ((visibility ("hidden")))
108 __attribute__ ((noreturn))
109 void
110 __chk_fail_overflow (void) {
111 __chk_fail("detected buffer overflow");
112 }
113
114 __attribute__ ((visibility ("hidden")))
115 __attribute__ ((noreturn))
116 void
117 __chk_fail_overlap (void) {
118 __chk_fail("detected source and destination buffer overlap");
119 }
120
121
122 __attribute__ ((visibility ("hidden")))
123 void
124 __chk_overlap (const void *_a, size_t an, const void *_b, size_t bn) {
125 uintptr_t a = (uintptr_t)_a;
126 uintptr_t b = (uintptr_t)_b;
127
128 if (__builtin_expect(an == 0 || bn == 0, 0)) {
129 return;
130 } else if (__builtin_expect(a == b, 0)) {
131 __chk_fail_overlap();
132 } else if (a < b) {
133 if (__builtin_expect(a + an > b, 0))
134 __chk_fail_overlap();
135 } else { // b < a
136 if (__builtin_expect(b + bn > a, 0))
137 __chk_fail_overlap();
138 }
139 }