1

I am using OpenSSL in a multithreaded program in C and having issues. So I wrote a small program to try to narrow down what the problem is. The functions besides the main function were copy pasted from https://github.com/plenluno/openssl/blob/master/openssl/crypto/threads/mttest.c

My program is as follows.

   #include<stdio.h>  
   #include<stdlib.h>
   #include<stdarg.h>
   #include <strings.h>
   #include <string.h>
   #include <math.h>
   #include <sys/stat.h>
   #include <fcntl.h>
   #include <unistd.h>
   #include<omp.h>
   #include <openssl/bn.h>
   #include <openssl/dh.h>
   #include <openssl/crypto.h>
   #include <pthread.h>
   #include <openssl/lhash.h>
   #include <openssl/buffer.h> 
   #include <openssl/x509.h>
   #include <openssl/ssl.h>
   #include <openssl/err.h>

   static pthread_mutex_t *lock_cs;
   static long *lock_count;

   void pthreads_locking_callback(int mode, int type, char *file,
     int line)
  {
   #if 0
      fprintf(stderr,"thread=%4d mode=%s lock=%s %s:%d\n",
      CRYPTO_thread_id(),
      (mode&CRYPTO_LOCK)?"l":"u",
      (type&CRYPTO_READ)?"r":"w",file,line);
   #endif
   #if 0
     if (CRYPTO_LOCK_SSL_CERT == type)
     fprintf(stderr,"(t,m,f,l) %ld %d %s %d\n",
     CRYPTO_thread_id(),
     mode,file,line);
   #endif
   if (mode & CRYPTO_LOCK)
    {
    pthread_mutex_lock(&(lock_cs[type]));
    lock_count[type]++;
    }
    else
    {
    pthread_mutex_unlock(&(lock_cs[type]));
    }
   }

 unsigned long pthreads_thread_id(void)
 {
 unsigned long ret;

 ret=(unsigned long)pthread_self();
return(ret);
 }

void CRYPTO_thread_setup(void)
{
 int i;

 lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * 
  sizeof(pthread_mutex_t));
lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
for (i=0; i<CRYPTO_num_locks(); i++)
    {
    lock_count[i]=0;
    pthread_mutex_init(&(lock_cs[i]),NULL);
    }

CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
}

 void thread_cleanup(void)
 {
       int i;
       CRYPTO_set_locking_callback(NULL);
       for (i=0; i<CRYPTO_num_locks(); i++)
       {
           pthread_mutex_destroy(&(lock_cs[i]));
       }
  OPENSSL_free(lock_cs);
  OPENSSL_free(lock_count);
  }

  int main(){

   BN_CTX *ctx;
   ctx = BN_CTX_new();

   omp_set_num_threads(158);
   #pragma omp parallel
   {

          int ID = omp_get_thread_num();
          BIGNUM *b,*e,*r,*m;
          b = BN_new();
          e = BN_new();
          r = BN_new();
          m = BN_new();
          BN_set_word(b, 9);
          BN_set_word(e, 3);
          BN_set_word(m, 5);
          BN_mod_exp(r,b,e,m,ctx);
          char* result = BN_bn2dec(r);
          printf("\n thread = %d result = %s", ID, result); fflush(stdout);
          }

          thread_cleanup();

        }

I get the following error and backtrace, which tells me that BN_mod_exp(r,b,e,m,ctx) is the problem.

  Program received signal SIGSEGV, Segmentation fault.
  [Switching to Thread 0x7fffa9f69700 (LWP 151994)]
  0x00007ffff7a97bb6 in BN_CTX_end () from /lib/x86_64-linux-
  gnu/libcrypto.so.1.0.0
  (gdb) bt
  #0  0x00007ffff7a97bb6 in BN_CTX_end () from /lib/x86_64-linux-
  gnu/libcrypto.so.1.0.0
  #1  0x00007ffff7a940cd in BN_div () from /lib/x86_64-linux-
  gnu/libcrypto.so.1.0.0
  #2  0x00007ffff7aa3dff in BN_MONT_CTX_set () from /lib/x86_64-
  linux-gnu/libcrypto.so.1.0.0
  #3  0x00007ffff7a963e5 in BN_mod_exp_mont_word () from /lib/x86_64-
  linux-gnu/libcrypto.so.1.0.0
  #4  0x0000000000400fef in main._omp_fn.0 () at 
  debuggingsession.c:106
  #5  0x00007ffff77f734a in ?? () from /usr/lib/x86_64-linux-
  gnu/libgomp.so.1
  #6  0x00007ffff75d9184 in start_thread (arg=0x7fffa9f69700) at 
  pthread_create.c:312
  #7  0x00007ffff730603d in clone () at 
  ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
  (gdb) frame 4
   #4  0x0000000000400fef in main._omp_fn.0 () at 
   debuggingsession.c:106
  106       BN_mod_exp(r,b,e,m,ctx);
  (gdb) print r
  $1 = (BIGNUM *) 0x7fff8c000900
  (gdb) x 0x7fff8c000900
  0x7fff8c000900:   0x00000000
  (gdb) print b
   $2 = (BIGNUM *) 0x7fff8c0008c0
   (gdb) x 0x7fff8c0008c0
   0x7fff8c0008c0:  0x8c000940
   (gdb) x 0x8c000940
   0x8c000940:  Cannot access memory at address 0x8c000940
   (gdb) print b
   $3 = (BIGNUM *) 0x7fff8c0008c0
   (gdb) print e
   $4 = (BIGNUM *) 0x7fff8c0008e0
   (gdb) print m
   $5 = (BIGNUM *) 0x7fff8c000920
   (gdb) x

Update: I am using OpenSSL and OpenMP in a larger program, the above was just for debugging. In the larger program, I set up multiple threads and each is supposed to write to its own file (not the same file). From here: https://en.wikibooks.org/wiki/OpenSSL/Initialization they say that thread callbacks have to be set up before the initialization functions. I am assuming what this means is that first we call CRYPTO_thread_setup(), and then the OpenSSL library initialization functions. Where does CRYPTO_thread_setup() have to be called from, is it immediately after the first #pragma omp parallel and before the opening brace? When I put it there, along with the library initialization functions, I still get segmentation faults, this time relating to using fclose() within the threads. Any ideas on why this could be happening?

MSJ
  • 97
  • 1
  • 10
  • I believe you need to call `CRYPTO_thread_setup` in `main` to setup the locks. Also see [Memory leaks and seg faults when using OpenMP and OpenSSL](https://stackoverflow.com/q/22906207/608639) and [Library Initialization](https://wiki.openssl.org/index.php/Library_Initialization) on the OpenSSL wiki. Valgrind without OpenMP should show the problem as uninitialized reads. – jww Jan 20 '18 at 12:24
  • Thanks jww, kindly see update to question. – MSJ Jan 21 '18 at 15:19

0 Answers0