Print this page
1667 pkcs11 may deadlock when multi-threaded consumers fork

@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>

@@ -31,10 +32,11 @@
 #include <locale.h>
 #include <stdarg.h>
 #include <cryptoutil.h>
 #include <pthread.h>
 
+#pragma init(pkcs11_random_init)
 
 static pthread_mutex_t  random_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t  urandom_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 static pthread_mutex_t  random_seed_mutex = PTHREAD_MUTEX_INITIALIZER;

@@ -179,17 +181,17 @@
         (void) close(*fd);
         *fd = -1;
         (void) pthread_mutex_unlock(mtx);
 }
 
-void
+static void
 pkcs11_close_random(void)
 {
         pkcs11_close_common(&random_fd, &random_mutex);
 }
 
-void
+static void
 pkcs11_close_urandom(void)
 {
         pkcs11_close_common(&urandom_fd, &urandom_mutex);
 }
 

@@ -197,11 +199,11 @@
 pkcs11_close_random_seed(void)
 {
         pkcs11_close_common(&random_seed_fd, &random_seed_mutex);
 }
 
-void
+static void
 pkcs11_close_urandom_seed(void)
 {
         pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex);
 }
 

@@ -374,6 +376,48 @@
                 bytesleft--;
 
                 ((char *)dbuf)[i] = extrarand[bytesleft];
         }
         return (0);
+}
+
+static void
+pkcs11_random_prepare(void)
+{
+        /*
+         * NOTE - None of these are acquired more than one at a time.
+         * I can therefore acquire all four without fear of deadlock.
+         */
+        (void) pthread_mutex_lock(&random_mutex);
+        (void) pthread_mutex_lock(&urandom_mutex);
+        (void) pthread_mutex_lock(&random_seed_mutex);
+        (void) pthread_mutex_lock(&urandom_seed_mutex);
+}
+
+static void
+pkcs11_random_parent_post(void)
+{
+        /* Drop the mutexes and get back to work! */
+        (void) pthread_mutex_unlock(&urandom_seed_mutex);
+        (void) pthread_mutex_unlock(&random_seed_mutex);
+        (void) pthread_mutex_unlock(&urandom_mutex);
+        (void) pthread_mutex_unlock(&random_mutex);
+}
+
+static void
+pkcs11_random_child_post(void)
+{
+        pkcs11_random_parent_post();
+
+        /* Also, close the FDs, just in case. */
+        pkcs11_close_random();
+        pkcs11_close_urandom();
+        pkcs11_close_random_seed();
+        pkcs11_close_urandom_seed();
+}
+
+static void
+pkcs11_random_init(void)
+{
+        (void) pthread_atfork(pkcs11_random_prepare, pkcs11_random_parent_post,
+            pkcs11_random_child_post);
 }