Skip to content

Commit 8984480

Browse files
committed
Fix race condition with BIO methods initialization in libpq with threads
The libpq code in charge of creating per-connection SSL objects was prone to a race condition when loading the custom BIO methods needed by my_SSL_set_fd(). As BIO methods are stored as a static variable, the initialization of a connection could fail because it could be possible to have one thread refer to my_bio_methods while it is being manipulated by a second concurrent thread. This error has been introduced by 8bb14cd, that has removed ssl_config_mutex around the call of my_SSL_set_fd(), that itself sets the custom BIO methods used in libpq. Like previously, the BIO method initialization is now protected by the existing ssl_config_mutex, itself initialized earlier for WIN32. While on it, document that my_bio_methods is protected by ssl_config_mutex, as this can be easy to miss. Reported-by: Willi Mann Author: Willi Mann, Michael Paquier Discussion: https://postgr.es/m/e77abc4c-4d03-4058-a9d7-ef0035657e04@celonis.com Backpatch-through: 12
1 parent 9033e70 commit 8984480

File tree

1 file changed

+51
-22
lines changed

1 file changed

+51
-22
lines changed

src/interfaces/libpq/fe-secure-openssl.c

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,7 @@ PQsslAttribute(PGconn *conn, const char *attribute_name)
18351835
#define BIO_set_data(bio, data) (bio->ptr = data)
18361836
#endif
18371837

1838+
/* protected by ssl_config_mutex */
18381839
static BIO_METHOD *my_bio_methods;
18391840

18401841
static int
@@ -1900,6 +1901,15 @@ my_sock_write(BIO *h, const char *buf, int size)
19001901
static BIO_METHOD *
19011902
my_BIO_s_socket(void)
19021903
{
1904+
BIO_METHOD *res;
1905+
1906+
#ifdef ENABLE_THREAD_SAFETY
1907+
if (pthread_mutex_lock(&ssl_config_mutex))
1908+
return NULL;
1909+
#endif
1910+
1911+
res = my_bio_methods;
1912+
19031913
if (!my_bio_methods)
19041914
{
19051915
BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
@@ -1908,39 +1918,58 @@ my_BIO_s_socket(void)
19081918

19091919
my_bio_index = BIO_get_new_index();
19101920
if (my_bio_index == -1)
1911-
return NULL;
1921+
goto err;
19121922
my_bio_index |= (BIO_TYPE_DESCRIPTOR | BIO_TYPE_SOURCE_SINK);
1913-
my_bio_methods = BIO_meth_new(my_bio_index, "libpq socket");
1914-
if (!my_bio_methods)
1915-
return NULL;
1923+
res = BIO_meth_new(my_bio_index, "libpq socket");
1924+
if (!res)
1925+
goto err;
19161926

19171927
/*
19181928
* As of this writing, these functions never fail. But check anyway,
19191929
* like OpenSSL's own examples do.
19201930
*/
1921-
if (!BIO_meth_set_write(my_bio_methods, my_sock_write) ||
1922-
!BIO_meth_set_read(my_bio_methods, my_sock_read) ||
1923-
!BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) ||
1924-
!BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) ||
1925-
!BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) ||
1926-
!BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) ||
1927-
!BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
1928-
!BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom)))
1931+
if (!BIO_meth_set_write(res, my_sock_write) ||
1932+
!BIO_meth_set_read(res, my_sock_read) ||
1933+
!BIO_meth_set_gets(res, BIO_meth_get_gets(biom)) ||
1934+
!BIO_meth_set_puts(res, BIO_meth_get_puts(biom)) ||
1935+
!BIO_meth_set_ctrl(res, BIO_meth_get_ctrl(biom)) ||
1936+
!BIO_meth_set_create(res, BIO_meth_get_create(biom)) ||
1937+
!BIO_meth_set_destroy(res, BIO_meth_get_destroy(biom)) ||
1938+
!BIO_meth_set_callback_ctrl(res, BIO_meth_get_callback_ctrl(biom)))
19291939
{
1930-
BIO_meth_free(my_bio_methods);
1931-
my_bio_methods = NULL;
1932-
return NULL;
1940+
goto err;
19331941
}
19341942
#else
1935-
my_bio_methods = malloc(sizeof(BIO_METHOD));
1936-
if (!my_bio_methods)
1937-
return NULL;
1938-
memcpy(my_bio_methods, biom, sizeof(BIO_METHOD));
1939-
my_bio_methods->bread = my_sock_read;
1940-
my_bio_methods->bwrite = my_sock_write;
1943+
res = malloc(sizeof(BIO_METHOD));
1944+
if (!res)
1945+
goto err;
1946+
memcpy(res, biom, sizeof(BIO_METHOD));
1947+
res->bread = my_sock_read;
1948+
res->bwrite = my_sock_write;
19411949
#endif
19421950
}
1943-
return my_bio_methods;
1951+
1952+
my_bio_methods = res;
1953+
1954+
#ifdef ENABLE_THREAD_SAFETY
1955+
pthread_mutex_unlock(&ssl_config_mutex);
1956+
#endif
1957+
1958+
return res;
1959+
1960+
err:
1961+
#ifdef HAVE_BIO_METH_NEW
1962+
if (res)
1963+
BIO_meth_free(res);
1964+
#else
1965+
if (res)
1966+
free(res);
1967+
#endif
1968+
1969+
#ifdef ENABLE_THREAD_SAFETY
1970+
pthread_mutex_unlock(&ssl_config_mutex);
1971+
#endif
1972+
return NULL;
19441973
}
19451974

19461975
/* This should exactly match OpenSSL's SSL_set_fd except for using my BIO */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy