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__ 47typedef bool BOOL; 48#else 49typedef 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) 58static 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 65pthread_once_t __security_debug_once = PTHREAD_ONCE_INIT; 66static const char *gDebugScope; 67static CFMutableSetRef scopeSet; 68static bool negate = false; 69 70static 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 111static CFMutableArrayRef sSecurityLogHandlers; 112 113static 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 142static void clean_aslclient(void *client) 143{ 144 asl_close(client); 145} 146 147static 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 164void __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 192void __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 213void add_security_log_hanlder(security_log_handler handler) 214{ 215 CFArrayAppendValue(get_log_handlers(), handler); 216} 217 218static 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 229void __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 252void __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 264static 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 290void __security_simulatecrash(CFStringRef reason, uint32_t code) 291{ 292 secerror("Simulating crash, reason: %@, code=%08x", reason, code); 293 __security_simulatecrash_link(reason, code); 294} 295