]> git.saurik.com Git - apple/security.git/blob - utilities/src/debugging.c
Security-55471.14.tar.gz
[apple/security.git] / utilities / src / debugging.c
1 /*
2 * Copyright (c) 2006-2010 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
25 /*
26 * debugging.c - non-trivial debug support
27 */
28 #include "utilities/debugging.h"
29 #include "utilities/SecCFWrappers.h"
30 #include <CoreFoundation/CFSet.h>
31 #include <CoreFoundation/CFString.h>
32
33 #include <dispatch/dispatch.h>
34
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <pthread.h>
40 #include <asl.h>
41
42 /** begin: For SimulateCrash **/
43 #include <dlfcn.h>
44 #include <mach/mach.h>
45 /// Type to represent a boolean value.
46 #if TARGET_OS_IPHONE && __LP64__
47 typedef bool BOOL;
48 #else
49 typedef signed char BOOL;
50 // BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C"
51 // even if -funsigned-char is used.
52 #endif
53 /** end: For SimulateCrash **/
54
55 #define MAX_SCOPE_LENGTH 12
56
57 #if !defined(NDEBUG)
58 static CFStringRef copyScopeName(const char *scope, CFIndex scopeLen) {
59 if (scopeLen > MAX_SCOPE_LENGTH)
60 scopeLen = MAX_SCOPE_LENGTH - 1;
61 return CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)scope,
62 scopeLen, kCFStringEncodingUTF8, false);
63 }
64
65 pthread_once_t __security_debug_once = PTHREAD_ONCE_INIT;
66 static const char *gDebugScope;
67 static CFMutableSetRef scopeSet;
68 static bool negate = false;
69
70 static void __security_debug_init(void) {
71 const char *cur_scope = gDebugScope = getenv("DEBUGSCOPE");
72 if (cur_scope) {
73 if (!strcmp(cur_scope, "all")) {
74 scopeSet = NULL;
75 negate = true;
76 } else if (!strcmp(cur_scope, "none")) {
77 scopeSet = NULL;
78 negate = false;
79 } else {
80 scopeSet = CFSetCreateMutable(kCFAllocatorDefault, 0,
81 &kCFTypeSetCallBacks);
82 if (cur_scope[0] == '-') {
83 negate = true;
84 cur_scope++;
85 } else {
86 negate = false;
87 }
88
89 const char *sep;
90 while ((sep = strchr(cur_scope, ','))) {
91 CFStringRef scopeName = copyScopeName(cur_scope,
92 sep - cur_scope);
93 CFSetAddValue(scopeSet, scopeName);
94 CFRelease(scopeName);
95 cur_scope = sep + 1;
96 }
97
98 CFStringRef scopeName = copyScopeName(cur_scope,
99 strlen(cur_scope));
100 CFSetAddValue(scopeSet, scopeName);
101 CFRelease(scopeName);
102 }
103 } else {
104 scopeSet = NULL;
105 negate = false;
106 }
107 }
108
109 #endif
110
111 static CFMutableArrayRef sSecurityLogHandlers;
112
113 static CFMutableArrayRef get_log_handlers()
114 {
115 static dispatch_once_t handlers_once;
116
117 dispatch_once(&handlers_once, ^{
118 sSecurityLogHandlers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
119
120 CFArrayAppendValue(sSecurityLogHandlers, ^(const char *level, CFStringRef scope, const char *function,
121 const char *file, int line, CFStringRef message){
122 CFStringRef logStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %s %@\n"), scope ? scope : CFSTR(""), function, message);
123 CFStringPerformWithCString(logStr, ^(const char *logMsg) {
124 aslmsg msg = asl_new(ASL_TYPE_MSG);
125 if (scope) {
126 CFStringPerformWithCString(scope, ^(const char *scopeStr) {
127 asl_set(msg, ASL_KEY_FACILITY, scopeStr);
128 });
129 }
130 asl_set(msg, ASL_KEY_LEVEL, level);
131 asl_set(msg, ASL_KEY_MSG, logMsg);
132 asl_send(NULL, msg);
133 asl_free(msg);
134 });
135 CFReleaseSafe(logStr);
136 });
137 });
138
139 return sSecurityLogHandlers;
140 }
141
142 static void clean_aslclient(void *client)
143 {
144 asl_close(client);
145 }
146
147 static aslclient get_aslclient()
148 {
149 static dispatch_once_t once;
150 static pthread_key_t asl_client_key;
151 dispatch_once(&once, ^{
152 pthread_key_create(&asl_client_key, clean_aslclient);
153 });
154 aslclient client = pthread_getspecific(asl_client_key);
155 if (!client) {
156 client = asl_open(NULL, "SecAPI", 0);
157 asl_set_filter(client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
158 pthread_setspecific(asl_client_key, client);
159 }
160
161 return client;
162 }
163
164 void __security_trace_enter_api(const char *api, CFStringRef format, ...)
165 {
166 aslmsg msg = asl_new(ASL_TYPE_MSG);
167 asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_DEBUG);
168 asl_set(msg, "SecAPITrace", api);
169 asl_set(msg, "ENTER", "");
170 va_list args;
171 va_start(args, format);
172 if (format) {
173 CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
174 va_end(args);
175 CFStringPerformWithCString(message, ^(const char *utf8Str) {
176 asl_set(msg, ASL_KEY_MSG, utf8Str);
177 });
178 CFReleaseSafe(message);
179 }
180
181 {
182 char stack_info[80];
183
184 snprintf(stack_info, sizeof(stack_info), "C%p F%p", __builtin_return_address(1), __builtin_frame_address(2));
185 asl_set(msg, "CALLER", stack_info);
186 }
187
188 asl_send(get_aslclient(), msg);
189 asl_free(msg);
190 }
191
192 void __security_trace_return_api(const char *api, CFStringRef format, ...)
193 {
194 aslmsg msg = asl_new(ASL_TYPE_MSG);
195 asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_DEBUG);
196 asl_set(msg, "SecAPITrace", api);
197 asl_set(msg, "RETURN", "");
198 va_list args;
199 va_start(args, format);
200 if (format) {
201 CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args);
202 va_end(args);
203 CFStringPerformWithCString(message, ^(const char *utf8Str) {
204 asl_set(msg, ASL_KEY_MSG, utf8Str);
205 });
206 CFReleaseSafe(message);
207 }
208 asl_send(get_aslclient(), msg);
209 asl_free(msg);
210 }
211
212
213 void add_security_log_hanlder(security_log_handler handler)
214 {
215 CFArrayAppendValue(get_log_handlers(), handler);
216 }
217
218 static void __security_log_msg(const char *level, CFStringRef scope, const char *function,
219 const char *file, int line, CFStringRef message)
220 {
221
222 CFArrayForEach(get_log_handlers(), ^(const void *value) {
223 security_log_handler handler = (security_log_handler) value;
224
225 handler(level, scope, function, file, line, message);
226 });
227 }
228
229 void __security_debug(CFStringRef scope, const char *function,
230 const char *file, int line, CFStringRef format, ...)
231 {
232 #if !defined(NDEBUG)
233 pthread_once(&__security_debug_once, __security_debug_init);
234
235 /* Check if scope is enabled. */
236 if (scope && ((scopeSet && negate == CFSetContainsValue(scopeSet, scope)) ||
237 (!scopeSet && !negate)))
238 return;
239 #endif
240
241 va_list args;
242 va_start(args, format);
243 CFStringRef message = CFStringCreateWithFormatAndArguments(
244 kCFAllocatorDefault, NULL, format, args);
245 va_end(args);
246
247 /* DEBUG scopes are logged as notice when enabled. */
248 __security_log_msg(ASL_STRING_NOTICE, scope, function, file, line, message);
249 CFRelease(message);
250 }
251
252 void __security_log(const char *level, CFStringRef scope, const char *function,
253 const char *file, int line, CFStringRef format, ...)
254 {
255 va_list args;
256 va_start(args, format);
257 CFStringRef message = CFStringCreateWithFormatAndArguments(
258 kCFAllocatorDefault, NULL, format, args);
259 va_end(args);
260 __security_log_msg(level, scope, function, file, line, message);
261 CFRelease(message);
262 }
263
264 static void __security_simulatecrash_link(CFStringRef reason, uint32_t code)
265 {
266 #if !TARGET_IPHONE_SIMULATOR
267 // Prototype defined in <CrashReporterSupport/CrashReporterSupport.h>, but objC only.
268 // Soft linking here so we don't link unless we hit this.
269 static BOOL (*__SimulateCrash)(pid_t pid, mach_exception_data_type_t exceptionCode, CFStringRef description);
270
271 static dispatch_once_t once = 0;
272 dispatch_once(&once, ^{
273 void *image = dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport", RTLD_NOW);
274 if (image)
275 __SimulateCrash = dlsym(image, "SimulateCrash");
276 else
277 __SimulateCrash = NULL;
278 });
279
280 if (__SimulateCrash)
281 __SimulateCrash(getpid(), code, reason);
282 else
283 secerror("SimulateCrash not available");
284 #else
285 secerror("SimulateCrash not available in iOS simulator");
286 #endif
287 }
288
289
290 void __security_simulatecrash(CFStringRef reason, uint32_t code)
291 {
292 secerror("Simulating crash, reason: %@, code=%08x", reason, code);
293 __security_simulatecrash_link(reason, code);
294 }