]> granicus.if.org Git - p11-kit/commitdiff
Add test case for bug 90289 (deadlock on C_Initialize() in child after fork)
authorDavid Woodhouse <David.Woodhouse@intel.com>
Wed, 3 Jun 2015 14:00:57 +0000 (15:00 +0100)
committerStef Walter <stefw@redhat.com>
Mon, 29 Jun 2015 11:49:13 +0000 (13:49 +0200)
Reviewed-by: Stef Walter <stefw@redhat.com>
p11-kit/test-proxy.c

index 96b9adaa036ed59844b83803b4a1f1766560894a..0fb270b73a30db3debcdb73cc0fdcbb3e60ce2f4 100644 (file)
@@ -148,6 +148,62 @@ test_deinit_after_fork (void)
        if (!WIFEXITED (st) || WEXITSTATUS(st) != 0)
                assert_fail("Child failed to C_Initialize() and C_Finalize()", NULL);
 
+}
+
+static void
+test_initialize_child (void)
+{
+       CK_FUNCTION_LIST_PTR proxy;
+       CK_RV rv;
+       pid_t pid;
+       int st;
+
+       rv = C_GetFunctionList (&proxy);
+       assert (rv == CKR_OK);
+
+       assert (p11_proxy_module_check (proxy));
+
+       rv = proxy->C_Initialize(NULL);
+       assert_num_eq (rv, CKR_OK);
+
+       pid = fork ();
+       if (!pid) {
+               /* The PKCS#11 Usage Guide (v2.40) advocates in ยง2.5.2 that
+                * a child should call C_Initialize() after forking, and
+                * then immediately C_Finalize() if it's not going to do
+                * anything more with the PKCS#11 token. In a multi-threaded
+                * program this is a violation of the POSIX standard, which
+                * puts strict limits on what you're allowed to do between
+                * fork and an eventual exec or exit. But some things (like
+                * pkcs11-helper and thus OpenVPN) do it anyway, and we
+                * need to cope... */
+
+               /* https://bugs.freedesktop.org/show_bug.cgi?id=90289 reports
+                * a deadlock when this happens. Catch it with SIGALRM... */
+               alarm(1);
+
+               rv = proxy->C_Initialize(NULL);
+               assert_num_eq (rv, CKR_OK);
+
+               rv = proxy->C_Finalize (NULL);
+               assert_num_eq (rv, CKR_OK);
+
+               exit(0);
+       }
+       assert (pid != -1);
+       waitpid(pid, &st, 0);
+
+       rv = proxy->C_Finalize (NULL);
+       assert_num_eq (rv, CKR_OK);
+
+       p11_proxy_module_cleanup ();
+
+       /* If the assertion fails, p11_kit_failed() doesn't return. So make
+        * sure we do all the cleanup before the (expected) failure, or it
+        * causes all the *later* tests to fail too! */
+       if (!WIFEXITED (st) || WEXITSTATUS(st) != 0)
+               assert_fail("Child failed to C_Initialize() and C_Finalize()", NULL);
+
 }
 #endif
 
@@ -231,6 +287,7 @@ main (int argc,
        p11_test (test_initialize_multiple, "/proxy/initialize-multiple");
 #ifndef _WIN32
        p11_test (test_deinit_after_fork, "/proxy/deinit-after-fork");
+       p11_test (test_initialize_child, "/proxy/initialize-child");
 #endif
 
        test_mock_add_tests ("/proxy");