diff options
author | Ivan Avdeev <me@w23.ru> | 2016-06-01 09:30:03 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2016-06-01 09:40:55 +0200 |
commit | 31c521b0470e57125ffcd0f1b0c6edf3b9af96c1 (patch) | |
tree | 66cc86d09114eb504564e6b1400d89a0ca7bea85 /lib/vtls/vtls.c | |
parent | 6cabd78531f80d5c6cd942ed1aa97eaa5ec080df (diff) |
vtls: fix ssl session cache race condition
Sessionid cache management is inseparable from managing individual
session lifetimes. E.g. for reference-counted sessions (like those in
SChannel and OpenSSL engines) every session addition and removal
should be accompanied with refcount increment and decrement
respectively. Failing to do so synchronously leads to a race condition
that causes symptoms like use-after-free and memory corruption.
This commit:
- makes existing session cache locking explicit, thus allowing
individual engines to manage lock's scope.
- fixes OpenSSL and SChannel engines by putting refcount management
inside this lock's scope in relevant places.
- adds these explicit locking calls to other engines that use
sessionid cache to accommodate for this change. Note, however,
that it is unknown whether any of these engines could also have
this race.
Bug: https://github.com/curl/curl/issues/815
Fixes #815
Closes #847
Diffstat (limited to 'lib/vtls/vtls.c')
-rw-r--r-- | lib/vtls/vtls.c | 38 |
1 files changed, 20 insertions, 18 deletions
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index ca505a71c..6a7c1ace6 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -330,6 +330,25 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, } /* + * Lock shared SSL session data + */ +void Curl_ssl_sessionid_lock(struct connectdata *conn) +{ + if(SSLSESSION_SHARED(conn->data)) + Curl_share_lock(conn->data, + CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); +} + +/* + * Unlock shared SSL session data + */ +void Curl_ssl_sessionid_unlock(struct connectdata *conn) +{ + if(SSLSESSION_SHARED(conn->data)) + Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION); +} + +/* * Check if there's a session ID for the given connection in the cache, and if * there's one suitable, it is provided. Returns TRUE when no entry matched. */ @@ -350,10 +369,8 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, return TRUE; /* Lock if shared */ - if(SSLSESSION_SHARED(data)) { - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + if(SSLSESSION_SHARED(data)) general_age = &data->share->sessionage; - } else general_age = &data->state.sessionage; @@ -382,10 +399,6 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, } } - /* Unlock */ - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); - return no_match; } @@ -418,9 +431,6 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) size_t i; struct SessionHandle *data=conn->data; - if(SSLSESSION_SHARED(data)) - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; @@ -429,9 +439,6 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) break; } } - - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); } /* @@ -481,7 +488,6 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, /* If using shared SSL session, lock! */ if(SSLSESSION_SHARED(data)) { - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); general_age = &data->share->sessionage; } else { @@ -514,10 +520,6 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->conn_to_port = conn_to_port; /* connect to port number */ store->remote_port = conn->remote_port; /* port number */ - /* Unlock */ - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); - if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); |