OpenSSL会话重用多线程崩溃

时间:2013-05-31 19:34:49

标签: c linux openssl

我有一个嵌入式应用程序,它使用OpenSSL v0.9.7e进行客户端ssl事务。我一直在使用与子线程共享的全局会话指针。它监视每个COM端口有一个线程。它在很大程度上起作用。然而,每隔一段时间(每500个左右的事务)它就会在SSL_connect()内部崩溃。我做了一点点,它似乎是自己删除会话。因此,我怀疑其中一个线程在它执行时处于事务中间。如果参考计数是>我会认为它不会删除它。 0

有没有人知道是否可以通过全局共享会话执行此操作?我应该每个线程使用一个会话(COM端口)。这是代码。为简洁起见,我省略了所有错误检查。

    int send_ssl_post(){
  BIO *bio;
  SSL *ssl;
  int ret = -1;
  int sockfd;
  int sslRet;

  ssl = NULL;

  g_ctx = setup_client_ctx( );
  ssl = SSL_new( g_ctx );
  SSL_set_session( ssl, g_session );
  sockfd = tcpConnect( url, true );
  bio = BIO_new_socket( sockfd, BIO_NOCLOSE );
  SSL_set_bio( ssl, bio, bio ); // SSL_set_bio cannot fail
  sslRet = SSL_connect( ssl );

  // free the session. We may change sessions below
  if ( g_session != NULL ) {
     SSL_SESSION_free( g_session );
  }

  // SSL write
  ret = SSL_write( ssl, data, strlen( data ) );

  ret = SSL_read( ssl, resp, respSize ); // time-out logic should be in

  g_session = SSL_get1_session( ssl );

  if ( ssl != NULL ) {
     SSL_shutdown( ssl );
     SSL_free( ssl );
  }

  if ( sockfd > 0 ){
     close( sockfd ); 
  }

  ERR_remove_state( 0 ); // free the memory that did not freed (buggy in this SSL version)
  return 0;
}

我还有两个thead锁定回调函数:

static void locking_function( int mode, int n, const char * file, int line ) {
   if ( mode & CRYPTO_LOCK ){
      //logger( DEBUG, "CRYPTO Lock file: %s, line: %d, n: %d", file, line, n );
      pthread_mutex_lock( &ssl_mutex_array[n] );
   } else {
      //logger( DEBUG, "CRYPTO Unlock file: %s, line: %d, n: %d", file, line, n );
      pthread_mutex_unlock( &ssl_mutex_array[n] );
   }
}

static unsigned long id_function( void ) {
   //logger( DEBUG, "CRYPTO Id function");
   return ((unsigned long) pthread_self());
}

int setupSSLThreadLock( void ) {
   int i;

   //logger( DEBUG, "setupSSLThreadLock with %d number of locks", CRYPTO_num_locks() );
   ssl_mutex_array = OPENSSL_malloc( CRYPTO_num_locks( ) * sizeof (pthread_mutex_t) );

   if ( !ssl_mutex_array ){
      return 0;
   }

   for ( i = 0; i < CRYPTO_num_locks( ); i++ ){
      pthread_mutex_init( &ssl_mutex_array[i], NULL );
   }
   CRYPTO_set_id_callback( id_function );
   CRYPTO_set_locking_callback( locking_function );
   return 1;
}

int cleanupSSLThreadLock( void ) {
   int i;

   if ( ssl_mutex_array == NULL ){
      return 0;
   }
   CRYPTO_set_id_callback( NULL );
   CRYPTO_set_locking_callback( NULL );
   for ( i = 0; i < CRYPTO_num_locks( ); i++ ){
      pthread_mutex_destroy( &ssl_mutex_array[i] );
   }
   OPENSSL_free( ssl_mutex_array );
   ssl_mutex_array = NULL;
   return 1;
}

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

如果同时由两个线程运行send_ssl_post(),则表示您有竞争。考虑函数的这两部分:

  SSL_set_session( ssl, g_session );

  // free the session. We may change sessions below
  if ( g_session != NULL ) {
     SSL_SESSION_free( g_session );
  }

当一个线程在全局会话上调用SSL_SESSION_free()和其他一些线程尝试使用它来设置会话之间存在争用。如果首先发生自由,则尝试使用它的线程将访问释放的内存。

您可以互相排斥解决此种族问题。一个围绕SSL_set_session()电话。

acquire_session_lock();
if ( g_session != NULL ) {
    SSL_set_session( ssl, g_session );
}
release_session_lock();

SSL_SESSION_free()电话周围的另一个:

acquire_session_lock();
if ( g_session != NULL ) {
    SSL_SESSION_free( g_session );
    g_session = NULL;
}
release_session_lock();