Print this page
4912 soft_giant_mutex in pkcs11_softtoken stays held after fork

@@ -19,10 +19,12 @@
  * CDDL HEADER END
  */
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ *
+ * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 #include <strings.h>
 #include <errno.h>
 #include <cryptoutil.h>

@@ -126,16 +128,22 @@
 obj_to_be_freed_list_t obj_delay_freed;
 ses_to_be_freed_list_t ses_delay_freed;
 
 /* protects softtoken_initialized and access to C_Initialize/C_Finalize */
 pthread_mutex_t soft_giant_mutex = PTHREAD_MUTEX_INITIALIZER;
+/*
+ * ONLY SET TO TRUE BY softtoken_fork_prepare().
+ * ONLY SET TO FALSE BY softtoken_fork_after().
+ */
+boolean_t fork_prepared = B_FALSE;
 
 static CK_RV finalize_common(boolean_t force, CK_VOID_PTR pReserved);
 static void softtoken_init();
 static void softtoken_fini();
 static void softtoken_fork_prepare();
 static void softtoken_fork_after();
+static void softtoken_fork_after_droplocks(void);
 
 CK_RV
 C_Initialize(CK_VOID_PTR pInitArgs)
 {
 

@@ -409,20 +417,45 @@
  * is done if softtoken is ever unloaded without a C_Finalize() call.
  */
 static void
 softtoken_fini()
 {
+        int rc;
+
+        rc = pthread_mutex_trylock(&soft_giant_mutex);
+        /*
+         * Check to see if it was acquired by softtoken_fork_prepare().
+         */
+        if (rc == EBUSY && fork_prepared)
+                rc = 0;
+
+        if (rc != 0) {
+                /*
+                 * I don't know WHAT just happened, but it's pretty bad.  Grab
+                 * the lock for real, even if it means deadlocking here.
+                 */
         (void) pthread_mutex_lock(&soft_giant_mutex);
+        } /* Else we acquired the lock and life is good. */
 
-        /* if we're not initilized, do not attempt to finalize */
-        if (!softtoken_initialized) {
-                (void) pthread_mutex_unlock(&soft_giant_mutex);
-                return;
+        /* Only finalize if we're initialized. */
+        if (softtoken_initialized) {
+                /*
+                 * We also have to DROP all of the other locks that
+                 * softtoken_fork_prepare did IF it was prepared, because
+                 * finalize_common() is going to pick them right back up.
+                 */
+                if (fork_prepared)
+                        softtoken_fork_after_droplocks();
+                (void) finalize_common(B_TRUE, NULL_PTR);
+                /* ASSERT(!softtoken_initialized); */
         }
 
-        (void) finalize_common(B_TRUE, NULL_PTR);
-
+        /*
+         * If we don't want to drop the lock, we assume softtoken_fork_after()
+         * will get called.
+         */
+        if (!fork_prepared)
         (void) pthread_mutex_unlock(&soft_giant_mutex);
 }
 
 CK_RV
 C_GetInfo(CK_INFO_PTR pInfo)

@@ -494,11 +527,11 @@
  * 6. all soft_session_list mutexes via soft_acquire_all_session_mutexes()
  * 7. obj_delay_freed.obj_to_be_free_mutex;
  * 8. ses_delay_freed.ses_to_be_free_mutex
  */
 void
-softtoken_fork_prepare()
+softtoken_fork_prepare(void)
 {
         (void) pthread_mutex_lock(&soft_giant_mutex);
         if (softtoken_initialized) {
                 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
                 (void) pthread_mutex_lock(&soft_slot.slot_mutex);

@@ -508,27 +541,33 @@
                 (void) pthread_mutex_lock(
                     &obj_delay_freed.obj_to_be_free_mutex);
                 (void) pthread_mutex_lock(
                     &ses_delay_freed.ses_to_be_free_mutex);
         }
+        fork_prepared = B_TRUE;
 }
 
-/*
- * Release in opposite order to softtoken_fork_prepare().
- * Function is used for parent and child.
- */
-void
-softtoken_fork_after()
+static void
+softtoken_fork_after_droplocks(void)
 {
-        if (softtoken_initialized) {
-                (void) pthread_mutex_unlock(
-                    &ses_delay_freed.ses_to_be_free_mutex);
-                (void) pthread_mutex_unlock(
-                    &obj_delay_freed.obj_to_be_free_mutex);
+        /* ASSERT(softtoken_initialized); */
+        (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
+        (void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
                 soft_release_all_session_mutexes(soft_session_list);
                 soft_release_all_session_mutexes(&token_session);
                 (void) pthread_mutex_unlock(&soft_slot.keystore_mutex);
                 (void) pthread_mutex_unlock(&soft_slot.slot_mutex);
                 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
-        }
+}
+
+/*
+ * Release in opposite order to softtoken_fork_prepare().
+ * Function is used for parent and child.
+ */
+void
+softtoken_fork_after(void)
+{
+        if (softtoken_initialized)
+                softtoken_fork_after_droplocks();
+        fork_prepared = B_FALSE;
         (void) pthread_mutex_unlock(&soft_giant_mutex);
 }