Thanks to visit codestin.com
Credit goes to github.com

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/[email protected] 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)