Skip to content

data race in Curl_ossl_seed #7296

Closed
Closed
@grrtrr

Description

@grrtrr

Thread sanitizer found a data race in seeding openssl state.

I did this

Ran AWS SDK with curl as its client, using the thead sanitizer.

curl/libcurl version

7.67.0

operating system

5.4.0-1049-aws #51~18.04.1-Ubuntu SMP Fri May 14 18:38:46 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Problem description

The thread sanitizer produced the following trace:

WARNING: ThreadSanitizer: data race (pid=28103)
  Read of size 1 at 0x7fecd59c1280 by thread T1:
    #0 Curl_ossl_seed <null> (libexternal_Scurl_Slibcurl.so+0x69a35)
    #1 ossl_connect_step1 <null> (libexternal_Scurl_Slibcurl.so+0x6d7b3)
    #2 ossl_connect_common <null> (libexternal_Scurl_Slibcurl.so+0x6f8bb)
    #3 Curl_ossl_connect_nonblocking <null> (libexternal_Scurl_Slibcurl.so+0x6fcc5)
    #4 Curl_ssl_connect_nonblocking <null> (libexternal_Scurl_Slibcurl.so+0x7144b)
    #5 https_connecting <null> (libexternal_Scurl_Slibcurl.so+0x27fb2)
    #6 Curl_http_connect <null> (libexternal_Scurl_Slibcurl.so+0x2a5cf)
    #7 multi_runsingle <null> (libexternal_Scurl_Slibcurl.so+0x3e173)
    #8 curl_multi_perform <null> (libexternal_Scurl_Slibcurl.so+0x3f335)
    #9 curl_easy_perform <null> (libexternal_Scurl_Slibcurl.so+0x202d7)
    #10 Aws::Http::CurlHttpClient::MakeRequest(std::shared_ptr<Aws::Http::HttpRequest> const&, Aws::Utils::RateLimits::RateLimiterInterface*, Aws::Utils::RateLimits::RateLimiterInterface*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0x138ae3)
    #11 Aws::Client::AWSClient::AttemptOneRequest(std::shared_ptr<Aws::Http::HttpRequest> const&, Aws::AmazonWebServiceRequest const&, char const*, char const*, char const*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0xc0819)
    #12 Aws::Client::AWSClient::AttemptExhaustively(Aws::Http::URI const&, Aws::AmazonWebServiceRequest const&, Aws::Http::HttpMethod, char const*, char const*, char const*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0xc2e8e)
    #13 Aws::Client::AWSXMLClient::MakeRequest(Aws::Http::URI const&, Aws::AmazonWebServiceRequest const&, Aws::Http::HttpMethod, char const*, char const*, char const*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0xc689e)
    #14 Aws::S3::S3Client::ListObjectsV2(Aws::S3::Model::ListObjectsV2Request const&) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-s3_Slibaws-s3.so+0x1c12af)

  Previous write of size 1 at 0x7fecd59c1280 by thread T2:
    #0 Curl_ossl_seed <null> (libexternal_Scurl_Slibcurl.so+0x69af6)
    #1 ossl_connect_step1 <null> (libexternal_Scurl_Slibcurl.so+0x6d7b3)
    #2 ossl_connect_common <null> (libexternal_Scurl_Slibcurl.so+0x6f8bb)
    #3 Curl_ossl_connect_nonblocking <null> (libexternal_Scurl_Slibcurl.so+0x6fcc5)
    #4 Curl_ssl_connect_nonblocking <null> (libexternal_Scurl_Slibcurl.so+0x7144b)
    #5 https_connecting <null> (libexternal_Scurl_Slibcurl.so+0x27fb2)
    #6 Curl_http_connect <null> (libexternal_Scurl_Slibcurl.so+0x2a5cf)
    #7 multi_runsingle <null> (libexternal_Scurl_Slibcurl.so+0x3e173)
    #8 curl_multi_perform <null> (libexternal_Scurl_Slibcurl.so+0x3f335)
    #9 curl_easy_perform <null> (libexternal_Scurl_Slibcurl.so+0x202d7)
    #10 Aws::Http::CurlHttpClient::MakeRequest(std::shared_ptr<Aws::Http::HttpRequest> const&, Aws::Utils::RateLimits::RateLimiterInterface*, Aws::Utils::RateLimits::RateLimiterInterface*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0x138ae3)
    #11 Aws::Client::AWSClient::AttemptOneRequest(std::shared_ptr<Aws::Http::HttpRequest> const&, Aws::AmazonWebServiceRequest const&, char const*, char const*, char const*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0xc0819)
    #12 Aws::Client::AWSClient::AttemptExhaustively(Aws::Http::URI const&, Aws::AmazonWebServiceRequest const&, Aws::Http::HttpMethod, char const*, char const*, char const*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0xc2e8e)
    #13 Aws::Client::AWSXMLClient::MakeRequest(Aws::Http::URI const&, Aws::AmazonWebServiceRequest const&, Aws::Http::HttpMethod, char const*, char const*, char const*) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-core_Slibaws-core.so+0xc689e)
    #14 Aws::S3::S3Client::ListObjectsV2(Aws::S3::Model::ListObjectsV2Request const&) const <null> (libthird_Uparty_Saws-cpp-sdk_Saws-s3_Slibaws-s3.so+0x1c12af)

  Location is global 'ssl_seeded.23703' of size 1 at 0x7fecd59c1280 (libexternal_Scurl_Slibcurl.so+0x000000089280)

SUMMARY: ThreadSanitizer: data race (...) in Curl_ossl_seed

This points to the following code:

// curl/lib/vtls/openssl.c 
static CURLcode Curl_ossl_seed(struct Curl_easy *data)
{
  /* we have the "SSL is seeded" boolean static to prevent multiple
     time-consuming seedings in vain */
  static bool ssl_seeded = FALSE;  // <=== HERE (size=1)
  char fname[256];
  
  if(ssl_seeded)  // <== 
    return CURLE_OK;
  
  if(rand_enough()) {
    /* OpenSSL 1.1.0+ will return here */
    ssl_seeded = TRUE;  // <==
    return CURLE_OK;
  }

Either of the following fixes the problem (the first needs to be cleaned up, since it only works on Linux):

 --- lib/vtls/openssl.c.orig     2021-06-24 12:32:32.394071075 -0400
+++ lib/vtls/openssl.c  2021-06-24 12:32:16.545889072 -0400
@@ -30,6 +30,7 @@
 #ifdef USE_OPENSSL

 #include <limits.h>
+#include <pthread.h>

 #include "urldata.h"
 #include "sendf.h"
@@ -452,15 +453,22 @@ static CURLcode Curl_ossl_seed(struct Cu
 { 
   /* we have the "SSL is seeded" boolean static to prevent multiple
      time-consuming seedings in vain */
+  static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
   static bool ssl_seeded = FALSE;
   char fname[256];

-  if(ssl_seeded)
+  pthread_mutex_lock(&lock);
+  if(ssl_seeded) {
+    pthread_mutex_unlock(&lock);
     return CURLE_OK;
+  }
+  pthread_mutex_unlock(&lock);

   if(rand_enough()) {
     /* OpenSSL 1.1.0+ will return here */
+    pthread_mutex_lock(&lock);
     ssl_seeded = TRUE;
+    pthread_mutex_unlock(&lock);
     return CURLE_OK;
   }

Without static variable:

--- lib/vtls/openssl.c
+++ lib/vtls/openssl.c
@@ -450,9 +450,7 @@
 
 static CURLcode Curl_ossl_seed(struct Curl_easy *data)
 {
-  /* we have the "SSL is seeded" boolean static to prevent multiple
-     time-consuming seedings in vain */
-  static bool ssl_seeded = FALSE;
+  bool ssl_seeded = FALSE;
   char fname[256];
 
   if(ssl_seeded)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions