Hi

There are several issues in SoftHSM when using threads and
C_CloseAllSessions.

I'm not a C++ programmer, but I believe the issue is that
C_CloseAllSessions 'delete's sessions although the sessions can be in
use in another thread - causing segmentation faults in the other thread.

The attached patch to the test suite easily demonstrates the problem on
my system. Ubuntu 12.04, SoftHSM rev 6958.

$ gdb --args ./checks -o
...
Program received signal SIGSEGV, Segmentation fault.
0x000000000040cc54 in C_GenerateRandom (hSession=<optimized out>, 
    pRandomData=0x7fffffffe0b0 "<snip>", 
    ulRandomLen=40) at ../../../src/lib/main.cpp:2756
2756      session->rng->randomize(pRandomData, ulRandomLen);
(gdb) list
2751      if(pRandomData == NULL_PTR) {
2752        DEBUG_MSG("C_GenerateRandom", "pRandomData must not be a
NULL_PTR");
2753        return CKR_ARGUMENTS_BAD;
2754      }
2755    
2756      session->rng->randomize(pRandomData, ulRandomLen);
2757    
2758      DEBUG_MSG("C_GenerateRandom", "OK");
2759      return CKR_OK;
2760    }
(gdb) 

So session->rng is now an invalid reference since C_CloseAllSessions did
'delete' on the session from another thread.

I've seen this problem in C_GenerateKeyPair (also due to session->rng)
and in unknown place(s) crashing out in sqlite as well.

/Fredrik

Index: checks/checks.h
===================================================================
--- checks/checks.h	(revision 6958)
+++ checks/checks.h	(working copy)
@@ -41,3 +41,4 @@
 void runEncryptCheck(unsigned int counter);
 void runDecryptCheck(unsigned int counter);
 void runSignVerifyCheck();
+void runThreadsCheck(unsigned int counter);
Index: checks/checks.c
===================================================================
--- checks/checks.c	(revision 6958)
+++ checks/checks.c	(working copy)
@@ -36,6 +36,8 @@
 #include <assert.h>
 #include <string.h>
 
+#include <pthread.h>
+
 CK_UTF8CHAR userPIN[] = {"123456"};
 CK_UTF8CHAR soPIN[] = {"12345678"};
 
@@ -61,6 +63,7 @@
   printf("-l\t\tTest encrypt functions\n");
   printf("-m\t\tTest decrypt functions\n");
   printf("-n\t\tTest all sign and verify mechanisms\n");
+  printf("-o\t\tTest with pthreads\n");
   printf("\n-z\t\tRun all tests\n");
 }
 
@@ -80,7 +83,7 @@
   /* Init token */
   inittoken();
 
-  while ((c = getopt(argc, argv, "abcdefghijklmnz")) != -1) {
+  while ((c = getopt(argc, argv, "abcdefghijklmnoz")) != -1) {
     switch(c) {
       case 'a':
         runInitCheck(5);
@@ -124,6 +127,9 @@
       case 'n':
         runSignVerifyCheck();
         break;
+      case 'o':
+        runThreadsCheck(5);
+        break;
       case 'z':
         runInitCheck(5);
         runInfoCheck(5);
@@ -138,6 +144,7 @@
         runEncryptCheck(5);
         runDecryptCheck(5);
         runSignVerifyCheck();
+	runThreadsCheck(5);
         break;
       default:
         usage();
@@ -1781,3 +1788,67 @@
 
   printf("OK\n");
 }
+
+static void *run_closeAll_thread()
+{
+  int i = 0;
+  CK_RV rv;
+
+  while (i++ < 10000) {
+    rv = C_CloseAllSessions(slotWithToken);
+    assert(rv == CKR_OK);
+  }
+
+  return NULL;
+}
+
+void runThreadsCheck(unsigned int counter) {
+  unsigned int i;
+
+  printf("Checking C_CloseAllSessions and C_GenerateRandom with pthreads: ");
+
+  for(i = 0; i < counter; i++) {
+    CK_RV rv;
+    CK_SESSION_HANDLE hSession[10];
+    CK_BYTE seed[] = {"Some random data"};
+    CK_BYTE randomData[40];
+    pthread_t closeAll_thread;
+    CK_C_INITIALIZE_ARGS init_args;
+    int res;
+
+    memset(&init_args, 0, sizeof(init_args));
+    init_args.flags = CKF_OS_LOCKING_OK;
+
+    rv = C_Initialize(&init_args);
+    assert(rv == CKR_OK);
+
+    rv = C_OpenSession(slotWithToken, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession[0]);
+    assert(rv == CKR_OK);
+
+    rv = C_SeedRandom(hSession[0], seed, sizeof(seed));
+    assert(rv == CKR_OK);
+
+    /* Create a thread to run C_CloseAllSessions repeatedly */
+    res = pthread_create(&closeAll_thread, NULL,
+			 run_closeAll_thread, NULL);
+    assert(res == 0);
+
+    /* C_GenerateRandom while sessions are being closed */
+
+    for (i = 0; i < 100; i++) {
+      rv = C_GenerateRandom(hSession[0], randomData, 40);
+      assert(rv == CKR_OK);
+    }
+
+    pthread_cancel(closeAll_thread);
+
+    res = pthread_join(closeAll_thread, NULL);
+    assert(res == 0);
+
+    rv = C_Finalize(NULL_PTR);
+    assert(rv == CKR_OK);
+
+  }
+
+  printf("OK\n");
+}
_______________________________________________
Opendnssec-user mailing list
[email protected]
https://lists.opendnssec.org/mailman/listinfo/opendnssec-user

Reply via email to