Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 01eca6a

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 bc3c8db commit 01eca6a

File tree

1 file changed

+42
-22
lines changed

1 file changed

+42
-22
lines changed

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

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,6 +1820,7 @@ PQsslAttribute(PGconn *conn, const char *attribute_name)
18201820
#define BIO_set_data(bio, data) (bio->ptr = data)
18211821
#endif
18221822

1823+
/* protected by ssl_config_mutex */
18231824
static BIO_METHOD *my_bio_methods;
18241825

18251826
static int
@@ -1885,6 +1886,13 @@ my_sock_write(BIO *h, const char *buf, int size)
18851886
static BIO_METHOD *
18861887
my_BIO_s_socket(void)
18871888
{
1889+
BIO_METHOD *res;
1890+
1891+
if (pthread_mutex_lock(&ssl_config_mutex))
1892+
return NULL;
1893+
1894+
res = my_bio_methods;
1895+
18881896
if (!my_bio_methods)
18891897
{
18901898
BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
@@ -1893,39 +1901,51 @@ my_BIO_s_socket(void)
18931901

18941902
my_bio_index = BIO_get_new_index();
18951903
if (my_bio_index == -1)
1896-
return NULL;
1904+
goto err;
18971905
my_bio_index |= (BIO_TYPE_DESCRIPTOR | BIO_TYPE_SOURCE_SINK);
1898-
my_bio_methods = BIO_meth_new(my_bio_index, "libpq socket");
1899-
if (!my_bio_methods)
1900-
return NULL;
1906+
res = BIO_meth_new(my_bio_index, "libpq socket");
1907+
if (!res)
1908+
goto err;
19011909

19021910
/*
19031911
* As of this writing, these functions never fail. But check anyway,
19041912
* like OpenSSL's own examples do.
19051913
*/
1906-
if (!BIO_meth_set_write(my_bio_methods, my_sock_write) ||
1907-
!BIO_meth_set_read(my_bio_methods, my_sock_read) ||
1908-
!BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) ||
1909-
!BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) ||
1910-
!BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) ||
1911-
!BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) ||
1912-
!BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
1913-
!BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom)))
1914+
if (!BIO_meth_set_write(res, my_sock_write) ||
1915+
!BIO_meth_set_read(res, my_sock_read) ||
1916+
!BIO_meth_set_gets(res, BIO_meth_get_gets(biom)) ||
1917+
!BIO_meth_set_puts(res, BIO_meth_get_puts(biom)) ||
1918+
!BIO_meth_set_ctrl(res, BIO_meth_get_ctrl(biom)) ||
1919+
!BIO_meth_set_create(res, BIO_meth_get_create(biom)) ||
1920+
!BIO_meth_set_destroy(res, BIO_meth_get_destroy(biom)) ||
1921+
!BIO_meth_set_callback_ctrl(res, BIO_meth_get_callback_ctrl(biom)))
19141922
{
1915-
BIO_meth_free(my_bio_methods);
1916-
my_bio_methods = NULL;
1917-
return NULL;
1923+
goto err;
19181924
}
19191925
#else
1920-
my_bio_methods = malloc(sizeof(BIO_METHOD));
1921-
if (!my_bio_methods)
1922-
return NULL;
1923-
memcpy(my_bio_methods, biom, sizeof(BIO_METHOD));
1924-
my_bio_methods->bread = my_sock_read;
1925-
my_bio_methods->bwrite = my_sock_write;
1926+
res = malloc(sizeof(BIO_METHOD));
1927+
if (!res)
1928+
goto err;
1929+
memcpy(res, biom, sizeof(BIO_METHOD));
1930+
res->bread = my_sock_read;
1931+
res->bwrite = my_sock_write;
19261932
#endif
19271933
}
1928-
return my_bio_methods;
1934+
1935+
my_bio_methods = res;
1936+
pthread_mutex_unlock(&ssl_config_mutex);
1937+
return res;
1938+
1939+
err:
1940+
#ifdef HAVE_BIO_METH_NEW
1941+
if (res)
1942+
BIO_meth_free(res);
1943+
#else
1944+
if (res)
1945+
free(res);
1946+
#endif
1947+
pthread_mutex_unlock(&ssl_config_mutex);
1948+
return NULL;
19291949
}
19301950

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

0 commit comments

Comments
 (0)