X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/threadTest/threadTest.cpp diff --git a/SecurityTests/clxutils/threadTest/threadTest.cpp b/SecurityTests/clxutils/threadTest/threadTest.cpp new file mode 100644 index 00000000..563ff398 --- /dev/null +++ b/SecurityTests/clxutils/threadTest/threadTest.cpp @@ -0,0 +1,496 @@ +/* + * Multithread exerciser - beat up on CSP, TP, and CL from multiple threads. + * + * Written by Doug Mitchell. + * + * + * Spawn a user-spec'd number of threads, each of which does the following: + * + * testThread(testParams) { + * roll the dice; + * depending on dieValue { + * cgVerify test; + * cgConstruct test; + * sslPing() test; + * etc.... + * } + * } + */ +#include +#include +#include +#include "testParams.h" +#include +#include +#include +#include +#include + +#include +#include + +/* + * As of 3/15/2001, can't link apps which use Security.framework against BSAFE. + */ +#define BSAFE_ENABLE 0 + +#define NUM_LOOPS 100 +#define NUM_THREADS 20 + +/* function for both test init and test proper */ +typedef int (*testFcn)(TestParams *testParams); + +/* one test */ +typedef struct { + testFcn testInit; + testFcn testRun; + const char *testName; + char enable; +} TestDef; + +/* the tests we know about */ + +#define CG_CONSTRUCT_ENABLE 1 /* leak free 12/19 */ +#define CG_VERIFY_ENABLE 1 /* leak free 12/19 */ +#define SIGN_VFY_ENABLE 1 /* leak free */ +#define SYM_TEST_ENABLE 1 /* leak free */ +#define TIME_ENABLE 0 /* normally off */ +#define SSL_PING_ENABLE 0 /* leak free 12/19 */ +#define GET_FIELDS_ENABLE 1 /* leak free */ +#define GET_CACHED_FLDS_ENABLE 1 /* leak free */ +#define DER_DECODE_ENABLE 0 +#define ATTACH_ENABLE 1 /* leak free */ +#define SEC_TRUST_ENABLE 0 /* works but leaks per 3737232 */ +#define KC_STATUS_ENABLE 0 /* currently fails: see 6368768 */ +#define DIGEST_CLIENT_ENABLE 1 +#define MDS_LOOKUP_ENABLE 1 /* leak free */ +#define CSSM_ERR_STR_ENABLE 0 /* leak free */ +#define TRUST_SETTINGS_ENABLE 1 +#define DB_SETTINGS_ENABLE 0 /* not thread safe */ +#define COPY_ROOTS_ENABLE 1 + +#if BSAFE_ENABLE +#define RSA_SIGN_ENABLE 1 +#define DES_ENABLE 1 +#else +#define RSA_SIGN_ENABLE 0 +#define DES_ENABLE 0 +#endif /* BSAFE_ENABLE */ +#define SSL_THRASH_ENABLE 0 +#define CSP_RAND_ENABLE 0 + +/* when adding to this table be sure to update setTestEnables() as well */ +TestDef testArray[] = { + { cgConstructInit, cgConstruct, "cgConstruct", CG_CONSTRUCT_ENABLE }, + { cgVerifyInit, cgVerify, "cgVerify", CG_VERIFY_ENABLE }, + { signVerifyInit, signVerify, "signVerify", SIGN_VFY_ENABLE }, + { symTestInit, symTest, "symTest", SYM_TEST_ENABLE }, + { timeInit, timeThread, "timeThread", TIME_ENABLE }, + { sslPingInit, sslPing, "sslPing", SSL_PING_ENABLE }, + { getFieldsInit, getFields, "getFields", GET_FIELDS_ENABLE }, + { getCachedFieldsInit, getCachedFields,"getCachedFields",GET_CACHED_FLDS_ENABLE}, + { attachTestInit, attachTest, "attachTest", ATTACH_ENABLE }, + { sslThrashInit, sslThrash, "sslThrash", SSL_THRASH_ENABLE }, + { cspRandInit, cspRand, "cspRand", CSP_RAND_ENABLE }, + { derDecodeInit, derDecodeTest, "derDecode", DER_DECODE_ENABLE }, + { secTrustEvalInit, secTrustEval, "secTrustEval", SEC_TRUST_ENABLE }, + { kcStatusInit, kcStatus, "kcStatus", KC_STATUS_ENABLE }, + { digestClientInit, digestClient, "digestClient", DIGEST_CLIENT_ENABLE}, + { mdsLookupInit, mdsLookup, "mdsLookup", MDS_LOOKUP_ENABLE }, + { cssmErrStrInit, cssmErrStr, "cssmErrStr", CSSM_ERR_STR_ENABLE }, + { trustSettingsInit, trustSettingsEval, "trustSettingsEval", TRUST_SETTINGS_ENABLE }, + { dbOpenCloseInit, dbOpenCloseEval, "dbOpenClose", DB_SETTINGS_ENABLE }, + { copyRootsInit, copyRootsTest, "copyRoots", COPY_ROOTS_ENABLE }, + #if BSAFE_ENABLE + { desInit, desTest, "desTest", DES_ENABLE }, + { rsaSignInit, rsaSignTest, "rsaSignTest", RSA_SIGN_ENABLE } + #endif +}; +#define NUM_THREAD_TESTS (sizeof(testArray) / sizeof(TestDef)) + +static void usage(char **argv) +{ + printf("Usage: %s [options]\n", argv[0]); + printf("Options:\n"); + printf(" l=loopCount (default = %d)\n", NUM_LOOPS); + printf(" t=threadCount (default = %d)\n", NUM_THREADS); + printf(" e[cvsytpfabdFSrDTkmCer] - enable specific tests\n"); + printf(" c=cgConstruct v=cgVerify s=signVerify y=symTest\n"); + printf(" t=timeThread p=sslPing f=getFields a=attach\n"); + printf(" b=bsafeSignVfy d=bsafeDES F=getCachedFields\n"); + printf(" S=sslThrash r=cspRand D=derDecode T=SecTrustEval\n"); + printf(" k=kcStatus m=mdsLookup C=digestClient e=cssmErrorStr\n"); + printf(" R=TrustSetting B=DBOpenClose o=copyRoots\n"); + printf(" o=test_specific_opts (see source for details)\n"); + printf(" a(bort on error)\n"); + printf(" r(un loop)\n"); + printf(" q(uiet)\n"); + printf(" v(erbose)\n"); + printf(" s(ilent)\n"); + printf(" h(elp)\n"); + exit(1); +} + +/* it happens from time to time on SSL ping */ +#include +void sigpipe(int sig) +{ + fflush(stdin); + printf("***SIGPIPE***\n"); +} + +/* common thread-safe routines */ +static Security::DevRandomGenerator devRand; + +CSSM_RETURN threadGetRandData( + const TestParams *testParams, + CSSM_DATA_PTR data, // mallocd by caller + unsigned numBytes) // how much to fill +{ + devRand.random(data->Data, numBytes); + data->Length = numBytes; + return CSSM_OK; +} + +/* delay a random amount, 0 _(printLock); + printf("%c", c); + fflush(stdout); +} + +/* + * Optionally start up a CFRunLoop. This is needed to field keychain event callbacks, used + * to maintain root cert cache coherency. + */ + +/* first we need something to register so we *have* a run loop */ +static OSStatus kcCacheCallback ( + SecKeychainEvent keychainEvent, + SecKeychainCallbackInfo *info, + void *context) +{ + return noErr; +} + +/* main thread has to wait for this to be set to know a run loop has been set up */ +static int runLoopInitialized = 0; + +/* this is the thread which actually runs the CFRunLoop */ +void *cfRunLoopThread(void *arg) +{ + OSStatus ortn = SecKeychainAddCallback(kcCacheCallback, + kSecTrustSettingsChangedEventMask, NULL); + if(ortn) { + printf("registerCacheCallbacks: SecKeychainAddCallback returned %d", (int32_t)ortn); + /* Not sure how this could ever happen - maybe if there is no run loop active? */ + return NULL; + } + runLoopInitialized = 1; + CFRunLoopRun(); + /* should not be reached */ + printf("\n*** Hey! CFRunLoopRun() exited!***\n"); + return NULL; +} + +static int startCFRunLoop() +{ + pthread_t runLoopThread; + + int result = pthread_create(&runLoopThread, NULL, cfRunLoopThread, NULL); + if(result) { + printf("***pthread_create returned %d, aborting\n", result); + return -1; + } + return 0; +} + +/* main pthread body */ +void *testThread(void *arg) +{ + TestParams *testParams = (TestParams *)arg; + int status; + + TestDef *thisTestDef = &testArray[testParams->testNum]; + status = thisTestDef->testRun(testParams); + if(!testParams->quiet) { + printf("\n...thread %d test %s exiting with status %d\n", + testParams->threadNum, thisTestDef->testName, status); + } + pthread_exit((void*)status); + /* NOT REACHED */ + return (void *)status; +} + +/* + * Set enables in testArray[] + */ +static void setOneEnable(testFcn f) +{ + unsigned dex; + for(dex=0; dexnumLoops = numLoops; + thisTest->verbose = verbose; + thisTest->quiet = quiet; + thisTest->threadNum = dex; + thisTest->cspHand = cspHand; + thisTest->clHand = clHand; + thisTest->tpHand = tpHand; + thisTest->testOpts = testOpts; + + if(dex < 10) { + /* 0..9 */ + thisTest->progressChar = '0' + dex; + } + else if(dex < 36) { + /* a..z */ + thisTest->progressChar = 'a' + dex - 10; + } + else { + /* A..Z and if X can run more threads than that, I'll be surprised */ + thisTest->progressChar = 'Z' + dex - 36; + } + } + + /* Adjust testArray for tests which are actually enabled */ + numValidTests = 0; + dex=0; + for(i=0; itestNum = genRand(0, numValidTests - 1); + + thisTestDef = &testArray[thisTest->testNum]; + if(!quiet) { + printf("...thread %d: test %s\n", dex, thisTestDef->testName); + } + result = thisTestDef->testInit(thisTest); + if(result) { + printf("***Error on %s init; aborting\n", thisTestDef->testName); + errCount++; + goto abort; + } + } + + + /* start up each thread */ + threadList = (pthread_t *)malloc(numThreads * sizeof(pthread_t)); + for(dex=0; dex