Skip to content

Commit aad2a63

Browse files
committed
Add locking around SSL_context usage in libpq
I've been working with Nick Phillips on an issue he ran into when trying to use threads with SSL client certificates. As it turns out, the call in initialize_SSL() to SSL_CTX_use_certificate_chain_file() will modify our SSL_context without any protection from other threads also calling that function or being at some other point and trying to read from SSL_context. To protect against this, I've written up the attached (based on an initial patch from Nick and much subsequent discussion) which puts locks around SSL_CTX_use_certificate_chain_file() and all of the other users of SSL_context which weren't already protected. Nick Phillips, much reworked by Stephen Frost Back-patch to 9.0 where we started loading the cert directly instead of using a callback.
1 parent ddef1a3 commit aad2a63

File tree

1 file changed

+53
-3
lines changed

1 file changed

+53
-3
lines changed

src/interfaces/libpq/fe-secure.c

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ static void SSLerrfree(char *buf);
9292

9393
static bool pq_init_ssl_lib = true;
9494
static bool pq_init_crypto_lib = true;
95+
96+
/*
97+
* SSL_context is currently shared between threads and therefore we need to be
98+
* careful to lock around any usage of it when providing thread safety.
99+
* ssl_config_mutex is the mutex that we use to protect it.
100+
*/
95101
static SSL_CTX *SSL_context = NULL;
96102

97103
#ifdef ENABLE_THREAD_SAFETY
@@ -253,6 +259,10 @@ pqsecure_open_client(PGconn *conn)
253259
/* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */
254260
conn->sigpipe_flag = false;
255261

262+
#ifdef ENABLE_THREAD_SAFETY
263+
if (pthread_mutex_lock(&ssl_config_mutex))
264+
return -1;
265+
#endif
256266
/* Create a connection-specific SSL object */
257267
if (!(conn->ssl = SSL_new(SSL_context)) ||
258268
!SSL_set_app_data(conn->ssl, conn) ||
@@ -265,9 +275,14 @@ pqsecure_open_client(PGconn *conn)
265275
err);
266276
SSLerrfree(err);
267277
close_SSL(conn);
278+
#ifdef ENABLE_THREAD_SAFETY
279+
pthread_mutex_unlock(&ssl_config_mutex);
280+
#endif
268281
return PGRES_POLLING_FAILED;
269282
}
270-
283+
#ifdef ENABLE_THREAD_SAFETY
284+
pthread_mutex_unlock(&ssl_config_mutex);
285+
#endif
271286
/*
272287
* Load client certificate, private key, and trusted CA certs.
273288
*/
@@ -999,8 +1014,9 @@ destroy_ssl_system(void)
9991014
CRYPTO_set_id_callback(NULL);
10001015

10011016
/*
1002-
* We don't free the lock array. If we get another connection in this
1003-
* process, we will just re-use it with the existing mutexes.
1017+
* We don't free the lock array or the SSL_context. If we get another
1018+
* connection in this process, we will just re-use them with the
1019+
* existing mutexes.
10041020
*
10051021
* This means we leak a little memory on repeated load/unload of the
10061022
* library.
@@ -1089,7 +1105,15 @@ initialize_SSL(PGconn *conn)
10891105
* understands which subject cert to present, in case different
10901106
* sslcert settings are used for different connections in the same
10911107
* process.
1108+
*
1109+
* NOTE: This function may also modify our SSL_context and therefore
1110+
* we have to lock around this call and any places where we use the
1111+
* SSL_context struct.
10921112
*/
1113+
#ifdef ENABLE_THREAD_SAFETY
1114+
if (pthread_mutex_lock(&ssl_config_mutex))
1115+
return -1;
1116+
#endif
10931117
if (SSL_CTX_use_certificate_chain_file(SSL_context, fnbuf) != 1)
10941118
{
10951119
char *err = SSLerrmessage();
@@ -1098,8 +1122,13 @@ initialize_SSL(PGconn *conn)
10981122
libpq_gettext("could not read certificate file \"%s\": %s\n"),
10991123
fnbuf, err);
11001124
SSLerrfree(err);
1125+
1126+
#ifdef ENABLE_THREAD_SAFETY
1127+
pthread_mutex_unlock(&ssl_config_mutex);
1128+
#endif
11011129
return -1;
11021130
}
1131+
11031132
if (SSL_use_certificate_file(conn->ssl, fnbuf, SSL_FILETYPE_PEM) != 1)
11041133
{
11051134
char *err = SSLerrmessage();
@@ -1108,10 +1137,18 @@ initialize_SSL(PGconn *conn)
11081137
libpq_gettext("could not read certificate file \"%s\": %s\n"),
11091138
fnbuf, err);
11101139
SSLerrfree(err);
1140+
#ifdef ENABLE_THREAD_SAFETY
1141+
pthread_mutex_unlock(&ssl_config_mutex);
1142+
#endif
11111143
return -1;
11121144
}
1145+
11131146
/* need to load the associated private key, too */
11141147
have_cert = true;
1148+
1149+
#ifdef ENABLE_THREAD_SAFETY
1150+
pthread_mutex_unlock(&ssl_config_mutex);
1151+
#endif
11151152
}
11161153

11171154
/*
@@ -1287,6 +1324,10 @@ initialize_SSL(PGconn *conn)
12871324
{
12881325
X509_STORE *cvstore;
12891326

1327+
#ifdef ENABLE_THREAD_SAFETY
1328+
if (pthread_mutex_lock(&ssl_config_mutex))
1329+
return -1;
1330+
#endif
12901331
if (SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL) != 1)
12911332
{
12921333
char *err = SSLerrmessage();
@@ -1295,6 +1336,9 @@ initialize_SSL(PGconn *conn)
12951336
libpq_gettext("could not read root certificate file \"%s\": %s\n"),
12961337
fnbuf, err);
12971338
SSLerrfree(err);
1339+
#ifdef ENABLE_THREAD_SAFETY
1340+
pthread_mutex_unlock(&ssl_config_mutex);
1341+
#endif
12981342
return -1;
12991343
}
13001344

@@ -1322,11 +1366,17 @@ initialize_SSL(PGconn *conn)
13221366
libpq_gettext("SSL library does not support CRL certificates (file \"%s\")\n"),
13231367
fnbuf);
13241368
SSLerrfree(err);
1369+
#ifdef ENABLE_THREAD_SAFETY
1370+
pthread_mutex_unlock(&ssl_config_mutex);
1371+
#endif
13251372
return -1;
13261373
#endif
13271374
}
13281375
/* if not found, silently ignore; we do not require CRL */
13291376
}
1377+
#ifdef ENABLE_THREAD_SAFETY
1378+
pthread_mutex_unlock(&ssl_config_mutex);
1379+
#endif
13301380

13311381
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, verify_cb);
13321382
}

0 commit comments

Comments
 (0)