Skip to content

Commit

Permalink
Free up space in the session cache before adding.
Browse files Browse the repository at this point in the history
Fixes #18690

In some circumstances, it's possible that when using an external
database for the session cache, that pulling in an entry from that
cache to the internal cache will cause the newly added entry to
be deleted from the internal cache. This is likely to happen when
the internal cache is set to have a small size, and the newly added
entry's timeout places it at the end of the cache list.

This could be fixed by updating the timestamp of the session (via
`SSL_SESSION_set_time()` or `SSL_SESSION_set_timeout()`) before
adding to the cache. But that may not be desireable.

Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #18905)

(cherry picked from commit 4842a27)
  • Loading branch information
tmshort authored and t8m committed Aug 1, 2022
1 parent f5c7331 commit 2db226c
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 11 deletions.
26 changes: 15 additions & 11 deletions ssl/ssl_sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -748,32 +748,36 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c)
c->time = time(NULL);
ssl_session_calculate_timeout(c);
}
SSL_SESSION_list_add(ctx, c);

if (s != NULL) {
/*
* existing cache entry -- decrement previously incremented reference
* count because it already takes into account the cache
*/

SSL_SESSION_free(s); /* s == c */
ret = 0;
} else {
if (s == NULL) {
/*
* new cache entry -- remove old ones if cache has become too large
* delete cache entry *before* add, so we don't remove the one we're adding!
*/

ret = 1;

if (SSL_CTX_sess_get_cache_size(ctx) > 0) {
while (SSL_CTX_sess_number(ctx) > SSL_CTX_sess_get_cache_size(ctx)) {
while (SSL_CTX_sess_number(ctx) >= SSL_CTX_sess_get_cache_size(ctx)) {
if (!remove_session_lock(ctx, ctx->session_cache_tail, 0))
break;
else
ssl_tsan_counter(ctx, &ctx->stats.sess_cache_full);
}
}
}

SSL_SESSION_list_add(ctx, c);

if (s != NULL) {
/*
* existing cache entry -- decrement previously incremented reference
* count because it already takes into account the cache
*/

SSL_SESSION_free(s); /* s == c */
ret = 0;
}
CRYPTO_THREAD_unlock(ctx->lock);
return ret;
}
Expand Down
26 changes: 26 additions & 0 deletions test/sslapitest.c
Original file line number Diff line number Diff line change
Expand Up @@ -2131,6 +2131,32 @@ static int execute_test_session(int maxprot, int use_int_cache,
goto end;
}
}
/*
* Make a small cache, force out all other sessions but
* sess2, try to add sess1, which should succeed. Then
* make sure it's there by checking the owners. Despite
* the timeouts, sess1 should have kicked out sess2
*/

/* Make sess1 expire before sess2 */
if (!TEST_long_gt(SSL_SESSION_set_time(sess1, 1000), 0)
|| !TEST_long_gt(SSL_SESSION_set_timeout(sess1, 1000), 0)
|| !TEST_long_gt(SSL_SESSION_set_time(sess2, 2000), 0)
|| !TEST_long_gt(SSL_SESSION_set_timeout(sess2, 2000), 0))
goto end;

if (!TEST_long_ne(SSL_CTX_sess_set_cache_size(sctx, 1), 0))
goto end;

/* Don't care about results - cache should only be sess2 at end */
SSL_CTX_add_session(sctx, sess1);
SSL_CTX_add_session(sctx, sess2);

/* Now add sess1, and make sure it remains, despite timeout */
if (!TEST_true(SSL_CTX_add_session(sctx, sess1))
|| !TEST_ptr(sess1->owner)
|| !TEST_ptr_null(sess2->owner))
goto end;

testresult = 1;

Expand Down

0 comments on commit 2db226c

Please sign in to comment.