8000 Fix SSL deadlock risk in libpq · sqlparser/postgres@1ba5fe8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1ba5fe8

Browse files
committed
Fix SSL deadlock risk in libpq
In libpq, we set up and pass to OpenSSL callback routines to handle locking. When we run out of SSL connections, we try to clean things up by de-registering the hooks. Unfortunately, we had a few calls into the OpenSSL library after these hooks were de-registered during SSL cleanup which lead to deadlocking. This moves the thread callback cleanup to be after all SSL-cleanup related OpenSSL library calls. I've been unable to reproduce the deadlock with this fix. In passing, also move the close_SSL call to be after unlocking our ssl_config mutex when in a failure state. While it looks pretty unlikely to be an issue, it could have resulted in deadlocks if we ended up in this code path due to something other than SSL_new failing. Thanks to Heikki for pointing this out. Back-patch to all supported versions; note that the close_SSL issue only goes back to 9.0, so that hunk isn't included in the 8.4 patch. Initially found and reported by Vesa-Matti J Kari; many thanks to both Heikki and Andres for their help running down the specific issue and reviewing the patch.
1 parent 9553d0f commit 1ba5fe8

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

src/interfaces/libpq/fe-secure.c

Lines changed: 22 additions & 2 deletions
10000
Original file line numberDiff line numberDiff line change
@@ -283,10 +283,11 @@ pqsecure_open_client(PGconn *conn)
283283
libpq_gettext("could not establish SSL connection: %s\n"),
284284
err);
285285
SSLerrfree(err);
286-
close_SSL(conn);
287286
#ifdef ENABLE_THREAD_SAFETY
288287
pthread_mutex_unlock(&ssl_config_mutex);
289288
#endif
289+
close_SSL(conn);
290+
290291
return PGRES_POLLING_FAILED;
291292
}
292293
#ifdef ENABLE_THREAD_SAFETY
@@ -1525,15 +1526,23 @@ open_client_SSL(PGconn *conn)
15251526
static void
15261527
close_SSL(PGconn *conn)
15271528
{
1529+
bool destroy_needed = false;
1530+
15281531
if (conn->ssl)
15291532
{
15301533
DECLARE_SIGPIPE_INFO(spinfo);
15311534

1535+
/*
1536+
* We can't destroy everything SSL-related here due to the possible
1537+
* later calls to OpenSSL routines which may need our thread
1538+
* callbacks, so set a flag here and check at the end.
1539+
*/
1540+
destroy_needed = true;
1541+
15321542
DISABLE_SIGPIPE(conn, spinfo, (void) 0);
15331543
SSL_shutdown(conn->ssl);
15341544
SSL_free(conn->ssl);
15351545
conn->ssl = NULL;
1536-
pqsecure_destroy();
15371546
/* We have to assume we got EPIPE */
15381547
REMEMBER_EPIPE(spinfo, true);
15391548
RESTORE_SIGPIPE(conn, spinfo);
@@ -1553,6 +1562,17 @@ close_SSL(PGconn *conn)
15531562
conn->engine = NULL;
15541563
}
15551564
#endif
1565+
1566+
/*
1567+
* This will remove our SSL locking hooks, if this is the last SSL
1568+
* connection, which means we must wait to call it until after all
1569+
* SSL calls have been made, otherwise we can end up with a race
1570+
* condition and possible deadlocks.
1571+
*
1572+
* See comments above destroy_ssl_system().
1573+
*/
1574+
if (destroy_needed)
1575+
pqsecure_destroy();
15561576
}
15571577

15581578
/*

0 commit comments

Comments
 (0)
0