[PATCH 1/2] bcrypt: Synchronize symmetric key access for encrypt and decrypt.

Paul Gofman pgofman at codeweavers.com
Tue Apr 20 05:48:46 CDT 2021


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
    Forza Horizon 4 crashes during entering multiplayer mode due to BCryptEncrypt and
    BCryptDecrypt being used from different threads with the same key using MODE_ID_GCM.
    Most of the time that is either glinc free() assertion or segfault inside gnutls function.

    While bcrypt functions are probably not thread safe in general on Windows, I suppose
    the native implementation does not modify any key data in encrypt and decrypt
    in this mode.

 dlls/bcrypt/bcrypt_internal.h |  1 +
 dlls/bcrypt/bcrypt_main.c     | 16 ++++++++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index eb136111509..efa1a463489 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -164,6 +164,7 @@ struct key_symmetric
     ULONG        vector_len;
     UCHAR       *secret;
     ULONG        secret_len;
+    CRITICAL_SECTION cs;
 };
 
 #define KEY_FLAG_LEGACY_DSA_V2  0x00000001
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index a1423dcd836..2ef26e81291 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -1480,6 +1480,7 @@ NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_
     if (!(block_size = get_block_size( alg ))) return STATUS_INVALID_PARAMETER;
 
     if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
+    InitializeCriticalSection( &key->u.s.cs );
     key->hdr.magic      = MAGIC_KEY;
     key->alg_id         = alg->id;
     key->u.s.mode       = alg->mode;
@@ -1588,6 +1589,8 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
         key_copy->u.s.block_size = key_orig->u.s.block_size;
         key_copy->u.s.secret     = buffer;
         key_copy->u.s.secret_len = key_orig->u.s.secret_len;
+
+        InitializeCriticalSection( &key_copy->u.s.cs );
     }
     else
     {
@@ -1613,6 +1616,7 @@ static void key_destroy( struct key *key )
         key_funcs->key_symmetric_destroy( key );
         heap_free( key->u.s.vector );
         heap_free( key->u.s.secret );
+        DeleteCriticalSection( &key->u.s.cs );
     }
     else
     {
@@ -1714,6 +1718,7 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
                                ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags )
 {
     struct key *key = handle;
+    NTSTATUS ret;
 
     TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len, padding, iv, iv_len, output,
            output_len, ret_len, flags );
@@ -1730,13 +1735,17 @@ NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
         return STATUS_NOT_IMPLEMENTED;
     }
 
-    return key_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+    EnterCriticalSection( &key->u.s.cs );
+    ret = key_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+    LeaveCriticalSection( &key->u.s.cs );
+    return ret;
 }
 
 NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv,
                                ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags )
 {
     struct key *key = handle;
+    NTSTATUS ret;
 
     TRACE( "%p, %p, %u, %p, %p, %u, %p, %u, %p, %08x\n", handle, input, input_len, padding, iv, iv_len, output,
            output_len, ret_len, flags );
@@ -1753,7 +1762,10 @@ NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG inp
         return STATUS_NOT_IMPLEMENTED;
     }
 
-    return key_decrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+    EnterCriticalSection( &key->u.s.cs );
+    ret = key_decrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags );
+    LeaveCriticalSection( &key->u.s.cs );
+    return ret;
 }
 
 NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHAR *value, ULONG size, ULONG flags )
-- 
2.30.2




More information about the wine-devel mailing list