#include "utilities/debugging.h"
#include "utilities/SecCFWrappers.h"
#include <CoreFoundation/CFSet.h>
#include <CoreFoundation/CFString.h>
#include <dispatch/dispatch.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <asl.h>
#include <dlfcn.h>
#include <mach/mach.h>
#if TARGET_OS_IPHONE && __LP64__
typedef bool BOOL;
#else
typedef signed char BOOL;
#endif
#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);
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);
__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
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);
}