1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-08 14:02:17 +03:00

Fix for CONC-604 and CONC-605:

This patch fixes a crash when reconnectiong via TLS.
This commit is contained in:
Georg Richter
2022-07-18 11:41:46 +02:00
parent dac298de61
commit 9a572bc548
8 changed files with 72 additions and 67 deletions

View File

@@ -145,6 +145,7 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int f
int ma_tls_get_protocol_version(MARIADB_TLS *ctls);
const char *ma_pvio_tls_get_protocol_version(MARIADB_TLS *ctls);
int ma_pvio_tls_get_protocol_version_id(MARIADB_TLS *ctls);
void ma_tls_set_connection(MYSQL *mysql);
/* Function prototypes */
MARIADB_TLS *ma_pvio_tls_init(MYSQL *mysql);
@@ -156,6 +157,7 @@ int ma_pvio_tls_verify_server_cert(MARIADB_TLS *ctls);
const char *ma_pvio_tls_cipher(MARIADB_TLS *ctls);
my_bool ma_pvio_tls_check_fp(MARIADB_TLS *ctls, const char *fp, const char *fp_list);
my_bool ma_pvio_start_ssl(MARIADB_PVIO *pvio);
void ma_pvio_tls_set_connection(MYSQL *mysql);
void ma_pvio_tls_end();
#endif /* _ma_tls_h_ */

View File

@@ -229,4 +229,9 @@ end:
}
return rc;
}
void ma_pvio_tls_set_connection(MYSQL *mysql)
{
return ma_tls_set_connection(mysql);
}
#endif /* HAVE_TLS */

View File

@@ -1830,6 +1830,11 @@ my_bool STDCALL mariadb_reconnect(MYSQL *mysql)
mysql_close(mysql);
*mysql=tmp_mysql;
mysql->net.pvio->mysql= mysql;
#ifdef HAVE_TLS
/* CONC-604: Set new connection handle */
if (mysql_get_ssl_cipher(mysql))
ma_pvio_tls_set_connection(mysql);
#endif
ma_net_clear(&mysql->net);
mysql->affected_rows= ~(unsigned long long) 0;
mysql->info= 0;

View File

@@ -50,12 +50,6 @@ static int my_verify_callback(gnutls_session_t ssl);
char tls_library_version[TLS_VERSION_LENGTH];
struct st_gnutls_data {
MYSQL *mysql;
gnutls_privkey_t key;
gnutls_pcert_st cert;
};
struct st_cipher_map {
unsigned char sid[2];
const char *iana_name;
@@ -799,18 +793,6 @@ const struct st_cipher_map tls_ciphers[]=
NULL}
};
/* free data assigned to the connection */
static void free_gnutls_data(struct st_gnutls_data *data)
{
if (data)
{
if (data->key)
gnutls_privkey_deinit(data->key);
gnutls_pcert_deinit(&data->cert);
free(data);
}
}
/* map the gnutls cipher suite (defined by key exchange algorithm, cipher
and mac algorithm) to the corresponding OpenSSL cipher name */
static const char *openssl_cipher_name(gnutls_kx_algorithm_t kx,
@@ -912,20 +894,19 @@ static void ma_tls_set_error(MYSQL *mysql, void *ssl, int ssl_errno)
alert_name= gnutls_alert_get_name(alert_desc);
snprintf(ssl_error, MAX_SSL_ERR_LEN, "fatal alert received: %s",
alert_name);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0,
ssl_error);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ssl_error);
return;
}
if ((ssl_error_reason= gnutls_strerror(ssl_errno)))
{
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, 0,
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ssl_error_reason);
return;
}
snprintf(ssl_error, MAX_SSL_ERR_LEN, "SSL errno=%d", ssl_errno);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ssl_error);
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
ssl_error);
}
@@ -1126,7 +1107,6 @@ void *ma_tls_init(MYSQL *mysql)
gnutls_session_t ssl= NULL;
gnutls_certificate_credentials_t ctx;
int ssl_error= 0;
struct st_gnutls_data *data= NULL;
pthread_mutex_lock(&LOCK_gnutls_config);
@@ -1139,11 +1119,7 @@ void *ma_tls_init(MYSQL *mysql)
if ((ssl_error = gnutls_init(&ssl, GNUTLS_CLIENT | GNUTLS_NONBLOCK | GNUTLS_NO_SIGNAL)) < 0)
goto error;
if (!(data= (struct st_gnutls_data *)calloc(1, sizeof(struct st_gnutls_data))))
goto error;
data->mysql= mysql;
gnutls_session_set_ptr(ssl, (void *)data);
gnutls_session_set_ptr(ssl, (void *)mysql);
/*
gnutls_certificate_set_retrieve_function2(GNUTLS_xcred, client_cert_callback);
*/
@@ -1159,7 +1135,6 @@ void *ma_tls_init(MYSQL *mysql)
pthread_mutex_unlock(&LOCK_gnutls_config);
return (void *)ssl;
error:
free_gnutls_data(data);
ma_tls_set_error(mysql, ssl, ssl_error);
gnutls_certificate_free_credentials(ctx);
if (ssl)
@@ -1194,12 +1169,9 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
{
gnutls_session_t ssl = (gnutls_session_t)ctls->ssl;
my_bool blocking;
MYSQL *mysql;
MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ssl);
MARIADB_PVIO *pvio;
int ret;
struct st_gnutls_data *data;
data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
mysql= data->mysql;
if (!mysql)
return 1;
@@ -1301,9 +1273,13 @@ ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
while ((rc= gnutls_record_recv((gnutls_session_t)ctls->ssl, (void *)buffer, length)) <= 0)
{
if (rc != GNUTLS_E_AGAIN && rc != GNUTLS_E_INTERRUPTED)
return rc;
break;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.read_timeout) < 1)
return rc;
break;
}
if (rc <= 0) {
MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ctls->ssl);
ma_tls_set_error(mysql, ctls->ssl, rc);
}
return rc;
}
@@ -1316,9 +1292,13 @@ ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
while ((rc= gnutls_record_send((gnutls_session_t)ctls->ssl, (void *)buffer, length)) <= 0)
{
if (rc != GNUTLS_E_AGAIN && rc != GNUTLS_E_INTERRUPTED)
return rc;
break;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.write_timeout) < 1)
return rc;
break;
}
if (rc <= 0) {
MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ctls->ssl);
ma_tls_set_error(mysql, ctls->ssl, rc);
}
return rc;
}
@@ -1328,14 +1308,11 @@ my_bool ma_tls_close(MARIADB_TLS *ctls)
if (ctls->ssl)
{
gnutls_certificate_credentials_t ctx;
struct st_gnutls_data *data=
(struct st_gnutls_data *)gnutls_session_get_ptr(ctls->ssl);
/* this would be the correct way, however can't detect afterwards
if the socket is closed or not, so we don't send encrypted
finish alert.
rc= gnutls_bye((gnutls_session_t )ctls->ssl, GNUTLS_SHUT_WR);
*/
free_gnutls_data(data);
gnutls_credentials_get(ctls->ssl, GNUTLS_CRD_CERTIFICATE, (void **)&ctx);
gnutls_certificate_free_keys(ctx);
gnutls_certificate_free_cas(ctx);
@@ -1372,10 +1349,7 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
static int my_verify_callback(gnutls_session_t ssl)
{
unsigned int status= 0;
struct st_gnutls_data *data= (struct st_gnutls_data *)gnutls_session_get_ptr(ssl);
MYSQL *mysql;
mysql= data->mysql;
MYSQL *mysql= (MYSQL *)gnutls_session_get_ptr(ssl);
CLEAR_CLIENT_ERROR(mysql);
@@ -1419,13 +1393,11 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
size_t fp_len= len;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
struct st_gnutls_data *data;
if (!ctls || !ctls->ssl)
return 0;
data= (struct st_gnutls_data *)gnutls_session_get_ptr(ctls->ssl);
mysql= (MYSQL *)data->mysql;
mysql= (MYSQL *)gnutls_session_get_ptr(ctls->ssl);
cert_list = gnutls_certificate_get_peers (ctls->ssl, &cert_list_size);
if (cert_list == NULL)
@@ -1454,4 +1426,9 @@ int ma_tls_get_protocol_version(MARIADB_TLS *ctls)
return gnutls_protocol_get_version(ctls->ssl) - 1;
}
void ma_tls_set_connection(MYSQL *mysql)
{
(void)gnutls_session_set_ptr(mysql->net.pvio->ctls->ssl, (void *)mysql);
}
#endif /* HAVE_GNUTLS */

View File

@@ -591,16 +591,14 @@ ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
int error= SSL_get_error((SSL *)ctls->ssl, rc);
if (error != SSL_ERROR_WANT_READ)
{
if (error == SSL_ERROR_SSL || errno == 0)
{
MYSQL *mysql= SSL_get_app_data(ctls->ssl);
ma_tls_set_error(mysql);
}
return rc;
}
break;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.read_timeout) < 1)
return rc;
break;
}
if (rc <= 0)
{
MYSQL *mysql= SSL_get_app_data(ctls->ssl);
ma_tls_set_error(mysql);
}
return rc;
}
@@ -614,16 +612,14 @@ ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
{
int error= SSL_get_error((SSL *)ctls->ssl, rc);
if (error != SSL_ERROR_WANT_WRITE)
{
if (error == SSL_ERROR_SSL || errno == 0)
{
MYSQL *mysql= SSL_get_app_data(ctls->ssl);
ma_tls_set_error(mysql);
}
return rc;
}
break;
if (pvio->methods->wait_io_or_timeout(pvio, TRUE, pvio->mysql->options.write_timeout) < 1)
return rc;
break;
}
if (rc <= 0)
{
MYSQL *mysql= SSL_get_app_data(ctls->ssl);
ma_tls_set_error(mysql);
}
return rc;
}
@@ -782,3 +778,8 @@ int ma_tls_get_protocol_version(MARIADB_TLS *ctls)
return SSL_version(ctls->ssl) & 0xFF;
}
void ma_tls_set_connection(MYSQL *mysql)
{
(void)SSL_set_app_data(mysql->net.pvio->ctls->ssl, mysql);
}

View File

@@ -560,3 +560,8 @@ unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int l
CertFreeCertificateContext(pRemoteCertContext);
return len;
}
void ma_tls_set_connection(MYSQL *mysql __attribute__((unused)))
{
return;
}

View File

@@ -685,13 +685,16 @@ int test_connection_timeout2(MYSQL *unused __attribute__((unused)))
SKIP_SKYSQL;
SKIP_MAXSCALE;
// SKIP_TLS;
mysql= mysql_init(NULL);
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (unsigned int *)&timeout);
mysql_options(mysql, MYSQL_INIT_COMMAND, "set @a:=SLEEP(6)");
mysql_options(mysql, MYSQL_INIT_COMMAND, "set @a:=SLEEP(7)");
start= time(NULL);
if (my_test_connect(mysql, hostname, username, password, schema, port, NULL, CLIENT_REMEMBER_OPTIONS))
{
elapsed= time(NULL) - start;
diag("elapsed: %lu", (unsigned long)elapsed);
diag("timeout error expected");
return FAIL;
}

View File

@@ -73,6 +73,13 @@ if (IS_SKYSQL(hostname)) \
#define SKIP_NOTLS
#endif
#define SKIP_TLS \
if (force_tls)\
{\
diag("Test doesn't work with TLS");\
return SKIP;\
}
MYSQL *mysql_default = NULL; /* default connection */
#define IS_MAXSCALE()\