[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]
Subject: PKCS#11 Usage Guide vs. POSIX issue
Hi, It has come to my attention that the PKCS#11 Usage Guide is making a recommendation which triggers POSIX-undefined behaviour. The recommendation in question is §2.5.2 of the Usage Guide: http://docs.oasis-open.org/pkcs11/pkcs11-ug/v2.40/cn02/pkcs11-ug-v2.40-cn02.html#_Toc406759987 It says that it is good Cryptoki programming practice to call C_Initialize() again "immediately" in the child process after fork(). This has been implemented in some cases by using a pthread_atfork() child handler and directly calling C_Initialize() from it, for any PKCS#11 providers which were loaded in the parent. That behaviour is problematic for a number of reasons, which I'll present in increasing order of importance: Firstly, in most cases all we're going to do after a fork is exec, so to call C_Initialize() is at best a gratuitous performance issue on every fork() call. Secondly, there are a number of PKCS#11 providers which simply don't cope. For PKCS#11 providers whose main development is not on POSIX systems, the whole concept of fork() is alien, and it's largely untested. So calling C_Initialize() again in the child might deadlock, or it might disrupt the state of the module in the *parent* such that it no longer works (to cite but two that I've actually seen in the last week — and those were OpenSC and p11-kit-proxy which *are* developed on Linux!). Third, there's the POSIX issue I reference in $SUBJECT... The pthread_atfork() documentation¹ says: "It is suggested that programs that use fork() call an exec function very soon afterwards in the child process, thus resetting all states. In the meantime, only a short list of async-signal-safe library routines are promised to be available." It then goes on to explain why pthread_atfork() doesn't really work for its original intended purpose, before concluding more forcefully and using the word 'requires' instead of 'suggested': "As explained, there is no suitable solution for functionality which requires non-atomic operations to be protected through mutexes and locks. This is why the POSIX.1 standard since the 1996 release requires that the child process after fork() in a multi-threaded process only calls async-signal-safe interfaces." The fork() documentation² does indeed say that, as well as: "When the application calls fork() from a signal handler and any of the fork handlers registered by pthread_atfork() calls a function that is not async-signal-safe, the behavior is undefined." The "short list of async-signal-safe library functions" is indeed short³. It certainly doesn't seem to be the case that C_Initialize() is guaranteed to call only functions on that short list. So calling C_Initialize() from within the atfork child handler would appear to trigger undefined behaviour according to POSIX. It would be useful, therefore, to change the PKCS#11 Usage Guide to reflect this. My personal preference might be to add a short paragraph warning that POSIX effectively forbids the child process from calling *any* functions of a PKCS#11 provider after fork() from a multi-threaded program, and also to recommend that C_Initialize() should *only* be called if the child process is going to be long-lived rather than immediately exiting or executing something else. Thanks. -- David Woodhouse Open Source Technology Centre David.Woodhouse@intel.com Intel Corporation ¹ http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfork.html ² http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html ³ http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03
Attachment:
smime.p7s
Description: S/MIME cryptographic signature
[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]