On Mon, Jul 09, 2001 at 09:44:29AM -0700, Travis Vitek wrote:

> This fix seems to work fine, but there is still a (small) potential
> problem...
> 
> Consider the situation where thread id 0 is valid (this is true for some
> systems). If one thread (thread id N) unsets the flags and releases the lock
> (ssleay_rand_bytes)
> 
>   crypto_lock_rand = 0;
>   locking_thread = 0;
>   CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
> 
> Another thread (thread id M) locks and starts to set the flags
> (ssleay_rand_bytes)
> 
>   CRYPTO_w_lock(CRYPTO_LOCK_RAND);
>   crypto_lock_rand = 1;
> 
> Finally, thread 0 does a check to see if it should lock or not...
> (ssleay_rand_add)
> 
>   do_not_lock = cypto_lock_rand && (locking_thread == CRYPTO_thread_id());
> 
> it will not lock as it should, because it thinks it owns the lock, which is
> actually owned by thread M... Not good!

You are absolutely correct.  Actually I was aware that 0 can be a
valid thread ID (this is one reason for using the 'crypto_lock_rand'
flag in addition to the 'locking_thread' variable, similar to a change
I did in crypto/mem_dbg.c earlier on), but obviously I missed this
particular race condition.  Thanks for sharing your observation.


> I believe that the fix is fairly simple...
> 
>   1. When setting 'crypto_lock_rand = 1', only do so after setting
> 'locking_thread = CRYPTO_thread_id()'... This will guarantee that a thread
> checking do_not_lock will not see crypto_lock_rand flag set until after the
> true locking_thread has been set.
> 
>         // md_rand.c:355 and md_rand.c:520
>         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
> 
>         crypto_lock_rand = 1;
>         locking_thread = CRYPTO_thread_id();
> 
>     would be written like this...
>         
>         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
> 
>         locking_thread = CRYPTO_thread_id();
>         crypto_lock_rand = 1;

This was also my guess when reading your above problem description.
Hopefully this is a sign that this time it is really correct.

Actually it can not be correct if access to 'unsigned long' values is
not atomic.  If I decide to be that pedantic (and I start to feel I
should), I have to introduce an additional lock for protecting access
to 'locking_thread'.  This does not add significant overhead as
this is only needed on the few occasions when 'crypto_lock_rand' is
set.


>   2. When setting 'crypto_lock_rand = 0', just leave locking_thread alone.
> This just removes an unnecessary assignment

True, 'crypto_lock_rand = 42' would have made just as much sense.
Well, at least this is technically not a bug (but it isn't good
programming style either).
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to