X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/c38e3ce98599a410a47dc10253faa4d5830f13b2..427c49bcad63d042b29ada2ac27e3dfc4845c779:/utilities/src/debugging.c?ds=inline diff --git a/utilities/src/debugging.c b/utilities/src/debugging.c new file mode 100644 index 00000000..462de8bb --- /dev/null +++ b/utilities/src/debugging.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +/* + * debugging.c - non-trivial debug support + */ +#include "utilities/debugging.h" +#include "utilities/SecCFWrappers.h" +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +/** begin: For SimulateCrash **/ +#include +#include +/// Type to represent a boolean value. +#if TARGET_OS_IPHONE && __LP64__ +typedef bool BOOL; +#else +typedef signed char BOOL; +// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" +// even if -funsigned-char is used. +#endif +/** end: For SimulateCrash **/ + +#define MAX_SCOPE_LENGTH 12 + +#if !defined(NDEBUG) +static CFStringRef copyScopeName(const char *scope, CFIndex scopeLen) { + if (scopeLen > MAX_SCOPE_LENGTH) + scopeLen = MAX_SCOPE_LENGTH - 1; + return CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)scope, + scopeLen, kCFStringEncodingUTF8, false); +} + +pthread_once_t __security_debug_once = PTHREAD_ONCE_INIT; +static const char *gDebugScope; +static CFMutableSetRef scopeSet; +static bool negate = false; + +static void __security_debug_init(void) { + const char *cur_scope = gDebugScope = getenv("DEBUGSCOPE"); + if (cur_scope) { + if (!strcmp(cur_scope, "all")) { + scopeSet = NULL; + negate = true; + } else if (!strcmp(cur_scope, "none")) { + scopeSet = NULL; + negate = false; + } else { + scopeSet = CFSetCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeSetCallBacks); + if (cur_scope[0] == '-') { + negate = true; + cur_scope++; + } else { + negate = false; + } + + const char *sep; + while ((sep = strchr(cur_scope, ','))) { + CFStringRef scopeName = copyScopeName(cur_scope, + sep - cur_scope); + CFSetAddValue(scopeSet, scopeName); + CFRelease(scopeName); + cur_scope = sep + 1; + } + + CFStringRef scopeName = copyScopeName(cur_scope, + strlen(cur_scope)); + CFSetAddValue(scopeSet, scopeName); + CFRelease(scopeName); + } + } else { + scopeSet = NULL; + negate = false; + } +} + +#endif + +static CFMutableArrayRef sSecurityLogHandlers; + +static CFMutableArrayRef get_log_handlers() +{ + static dispatch_once_t handlers_once; + + dispatch_once(&handlers_once, ^{ + sSecurityLogHandlers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); + + CFArrayAppendValue(sSecurityLogHandlers, ^(const char *level, CFStringRef scope, const char *function, + const char *file, int line, CFStringRef message){ + CFStringRef logStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ %s %@\n"), scope ? scope : CFSTR(""), function, message); + CFStringPerformWithCString(logStr, ^(const char *logMsg) { + aslmsg msg = asl_new(ASL_TYPE_MSG); + if (scope) { + CFStringPerformWithCString(scope, ^(const char *scopeStr) { + asl_set(msg, ASL_KEY_FACILITY, scopeStr); + }); + } + asl_set(msg, ASL_KEY_LEVEL, level); + asl_set(msg, ASL_KEY_MSG, logMsg); + asl_send(NULL, msg); + asl_free(msg); + }); + CFReleaseSafe(logStr); + }); + }); + + return sSecurityLogHandlers; +} + +static void clean_aslclient(void *client) +{ + asl_close(client); +} + +static aslclient get_aslclient() +{ + static dispatch_once_t once; + static pthread_key_t asl_client_key; + dispatch_once(&once, ^{ + pthread_key_create(&asl_client_key, clean_aslclient); + }); + aslclient client = pthread_getspecific(asl_client_key); + if (!client) { + client = asl_open(NULL, "SecAPI", 0); + asl_set_filter(client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + pthread_setspecific(asl_client_key, client); + } + + return client; +} + +void __security_trace_enter_api(const char *api, CFStringRef format, ...) +{ + aslmsg msg = asl_new(ASL_TYPE_MSG); + asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_DEBUG); + asl_set(msg, "SecAPITrace", api); + asl_set(msg, "ENTER", ""); + va_list args; + va_start(args, format); + if (format) { + CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args); + va_end(args); + CFStringPerformWithCString(message, ^(const char *utf8Str) { + asl_set(msg, ASL_KEY_MSG, utf8Str); + }); + CFReleaseSafe(message); + } + + { + char stack_info[80]; + + snprintf(stack_info, sizeof(stack_info), "C%p F%p", __builtin_return_address(1), __builtin_frame_address(2)); + asl_set(msg, "CALLER", stack_info); + } + + asl_send(get_aslclient(), msg); + asl_free(msg); +} + +void __security_trace_return_api(const char *api, CFStringRef format, ...) +{ + aslmsg msg = asl_new(ASL_TYPE_MSG); + asl_set(msg, ASL_KEY_LEVEL, ASL_STRING_DEBUG); + asl_set(msg, "SecAPITrace", api); + asl_set(msg, "RETURN", ""); + va_list args; + va_start(args, format); + if (format) { + CFStringRef message = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, format, args); + va_end(args); + CFStringPerformWithCString(message, ^(const char *utf8Str) { + asl_set(msg, ASL_KEY_MSG, utf8Str); + }); + CFReleaseSafe(message); + } + asl_send(get_aslclient(), msg); + asl_free(msg); +} + + +void add_security_log_hanlder(security_log_handler handler) +{ + CFArrayAppendValue(get_log_handlers(), handler); +} + +static void __security_log_msg(const char *level, CFStringRef scope, const char *function, + const char *file, int line, CFStringRef message) +{ + + CFArrayForEach(get_log_handlers(), ^(const void *value) { + security_log_handler handler = (security_log_handler) value; + + handler(level, scope, function, file, line, message); + }); +} + +void __security_debug(CFStringRef scope, const char *function, + const char *file, int line, CFStringRef format, ...) +{ +#if !defined(NDEBUG) + pthread_once(&__security_debug_once, __security_debug_init); + + /* Check if scope is enabled. */ + if (scope && ((scopeSet && negate == CFSetContainsValue(scopeSet, scope)) || + (!scopeSet && !negate))) + return; +#endif + + va_list args; + va_start(args, format); + CFStringRef message = CFStringCreateWithFormatAndArguments( + kCFAllocatorDefault, NULL, format, args); + va_end(args); + + /* DEBUG scopes are logged as notice when enabled. */ + __security_log_msg(ASL_STRING_NOTICE, scope, function, file, line, message); + CFRelease(message); +} + +void __security_log(const char *level, CFStringRef scope, const char *function, + const char *file, int line, CFStringRef format, ...) +{ + va_list args; + va_start(args, format); + CFStringRef message = CFStringCreateWithFormatAndArguments( + kCFAllocatorDefault, NULL, format, args); + va_end(args); + __security_log_msg(level, scope, function, file, line, message); + CFRelease(message); +} + +static void __security_simulatecrash_link(CFStringRef reason, uint32_t code) +{ +#if !TARGET_IPHONE_SIMULATOR + // Prototype defined in , but objC only. + // Soft linking here so we don't link unless we hit this. + static BOOL (*__SimulateCrash)(pid_t pid, mach_exception_data_type_t exceptionCode, CFStringRef description); + + static dispatch_once_t once = 0; + dispatch_once(&once, ^{ + void *image = dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport", RTLD_NOW); + if (image) + __SimulateCrash = dlsym(image, "SimulateCrash"); + else + __SimulateCrash = NULL; + }); + + if (__SimulateCrash) + __SimulateCrash(getpid(), code, reason); + else + secerror("SimulateCrash not available"); +#else + secerror("SimulateCrash not available in iOS simulator"); +#endif +} + + +void __security_simulatecrash(CFStringRef reason, uint32_t code) +{ + secerror("Simulating crash, reason: %@, code=%08x", reason, code); + __security_simulatecrash_link(reason, code); +}