Helgrind报告的OpenSSL libcrypto.1.0.0 CRYPTO_malloc()中可能存在的数据竞争条件

时间:2014-03-22 14:01:23

标签: c multithreading openssl

我在测试多线程(pthreads)应用程序时遇到问题,Helgrind在libcrypto.1.0.0中报告了CRYPTO_malloc()内的数百个可能的数据争用。

我已阅读并完全理解所有可用文档,包括Linux网络编程指南第255-259页和http://www.openssl.org/docs/crypto/threads.html

我的代码正在初始化静态和动态锁结构和回调,并注册回调线程ID:

CRYPTO_THREADID_set_callback(ssl_mitm_thread_id);
CRYPTO_set_dynlock_create_callback(ssl_mitm_dyn_create_lock);
CRYPTO_set_dynlock_lock_callback(ssl_mitm_dyn_locking_callback);
CRYPTO_set_dynlock_destroy_callback(ssl_mitm_dyn_destroy_lock);
ssl_mitm_lock_mutexes = (pthread_mutex_t*)malloc(CRYPTO_num_locks() *
  sizeof(pthread_mutex_t));
for(i = 0; i < CRYPTO_num_locks(); i++) {
  pthread_mutex_init(&ssl_mitm_lock_mutexes[i], NULL);
}
CRYPTO_set_locking_callback(ssl_mitm_locking_callback);

SSL_library_init();
SSL_load_error_strings();
...etc...

我已将调试语句添加到锁定回调函数中,而openSSL仅调用折旧的CRYPTO_set_locking_callback(),而不使用新的动态锁定接口。

即便如此,它正在调用旧的静态锁定函数,因此正在尝试进行线程同步,但是Helgrind仍然认为有很多可能的数据争用。大多数(如果不是全部)都在CRYPTO_malloc()中。

那么,这个Helgrind是否会过度热心,还是OpenSSL / libcrypto中的一个错误?

e.g。

==20093== ----------------------------------------------------------------
==20093==
==20093== Possible data race during write of size 4 at 0x63BA368 by thread #3
==20093== Locks held: none
==20093==    at 0x604F0FE: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==20093==    by 0x57F4186: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093==    by 0x57D20C4: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093==    by 0x57D62E1: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093==    by 0x57DF0B6: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
[snip] (SSL_connect() called)
==20093==
==20093== This conflicts with a previous write of size 4 by thread #6
==20093== Locks held: none
==20093==    at 0x604F0FE: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==20093==    by 0x57E1673: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093==    by 0x57DF359: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
[snip] (SSL_connect() called)
==20093==
==20093== ----------------------------------------------------------------

在CRYPTO_malloc()中还有其他数据争用示例,这些数据争用来自SSL_read,SSL_write,SSL_connect和SSL_accept等。

2 个答案:

答案 0 :(得分:2)

以下片段中的最后一行是Helgrind抱怨的代码行:

void *CRYPTO_malloc(int num, const char *file, int line)
        {
        void *ret = NULL;

        if (num <= 0) return NULL;

        allow_customize = 0;

allow_customize全局变量在静态初始化中初始化为1。此值用于确保在调用分配例程后不调用malloc自定义函数(CRYPTO_set_mem...和变量)。此值为0的设置是在锁之外完成的。从技术上讲,如果一个线程在另一个线程试图为CRYPTO_...alloc设置自定义函数时尝试调用CRYPTO函数,则存在竞争条件,但这可以被视为应用程序错误。

答案 1 :(得分:0)

这里定义了CRYPTO_malloc

$ grep -R CRYPTO_malloc *
...
crypto/mem.c:void *CRYPTO_malloc_locked(int num, const char *file, int line)
crypto/mem.c:void *CRYPTO_malloc(int num, const char *file, int line)
...

CRYPTO_malloc_locked试图将页面保留在内存中(而不是写入swap);而不是线程安全的分配器。

这是CRYPTO_malloc的作用:

void *CRYPTO_malloc(int num, const char *file, int line)
    {
    void *ret = NULL;

    ...
    ret = malloc_ex_func(num,file,line);

    ...
    return ret;
    }

malloc_ex_funcdefault_malloc_ex中设为CRYPTO_set_mem_functions。并default_malloc_ex。但我似乎无法找到default_malloc_ex的实现。

但是,CRYPTO_malloc_init具有以下内容:

#define CRYPTO_malloc_init()    CRYPTO_set_mem_functions( \
    malloc, realloc, free)

因此看起来正在使用C运行时的malloc

您使用的OpenSSL版本是否支持线程?您可以通过包含<openssl/openssl.con.h>进行测试,并测试是否定义了OPENSSL_THREADS

这也应该有效:

$ cat /usr/local/ssl/include/openssl/opensslconf.h | grep -B 1 -A 1 -i thread

#ifndef OPENSSL_THREADS
# define OPENSSL_THREADS
#endif