1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

Rework the static-memory heap hint fix

Heap hints are inherited from the CTX, and switching a static-memory SSL
to a CTX with a different heap is outside that model. Instead of freeing
through a stack-local hint that carries the creating pool,
wolfSSL_set_SSL_CTX() now refuses a CTX whose heap differs from the
current one. ssl->ctx->heap is then always the heap the SSL was created
from, so wolfSSL_free(), FreeSSL() and FreeSSL_StaticMemory() go back to
freeing through it.

Releasing the SSL heap hint last in wolfSSL_ResourceFree() stays, as the
DTLS 1.3, QUIC and peerSigSpec cleanups still free through ssl->heap.

FreeSSL_StaticMemory() now clears ssl_hint->stats before freeing the
stats block. When wolfSSL_new() fails before SetSSL_CTX(), ssl->ctx is
NULL and the stats block and the hint are freed through ssl->heap
itself, so wolfSSL_Free() wrote the connection statistics into the
freed stats block on both frees.

test_wolfSSL_set_SSL_CTX_static_heap checks that a switch to a second
pool or to a CTX without a heap, and from one to a pool, is refused and
leaves the SSL on its original CTX, while a switch between two CTXs on
the same heap still succeeds.
This commit is contained in:
Tobias Frauenschläger
2026-10-15 09:51:56 +02:00
parent 3b172fe050
commit b8891fa1a4
3 changed files with 85 additions and 24 deletions

View File

@@ -10240,16 +10240,12 @@ static void FreeSSL_StaticMemory(WOLFSSL* ssl)
/* avoid dereferencing a test value */
if (ssl->heap != (void*)WOLFSSL_HEAP_TEST) {
#endif
void* heap = ssl->ctx ? ssl->ctx->heap : ssl->heap;
#ifndef WOLFSSL_STATIC_MEMORY_LEAN
WOLFSSL_HEAP_HINT* ssl_hint = (WOLFSSL_HEAP_HINT*)ssl->heap;
WOLFSSL_HEAP_HINT poolHint;
#ifndef WOLFSSL_STATIC_MEMORY_LEAN
WOLFSSL_HEAP* ctx_heap;
#endif
WOLFSSL_MEM_CONN_STATS* stats;
/* ssl->ctx may have been swapped, so free into the creating pool */
XMEMSET(&poolHint, 0, sizeof(poolHint));
poolHint.memory = ssl_hint->memory;
#ifndef WOLFSSL_STATIC_MEMORY_LEAN
ctx_heap = ssl_hint->memory;
#ifndef SINGLE_THREADED
if (wc_LockMutex(&(ctx_heap->memory_mutex)) != 0) {
@@ -10274,10 +10270,13 @@ static void FreeSSL_StaticMemory(WOLFSSL* ssl)
/* check if tracking stats */
if (ctx_heap->flag & WOLFMEM_TRACK_STATS) {
XFREE(ssl_hint->stats, &poolHint, DYNAMIC_TYPE_SSL);
/* with ssl->ctx NULL, heap is ssl->heap and XFREE updates stats */
stats = ssl_hint->stats;
ssl_hint->stats = NULL;
XFREE(stats, heap, DYNAMIC_TYPE_SSL);
}
#endif /* !WOLFSSL_STATIC_MEMORY_LEAN */
XFREE(ssl->heap, &poolHint, DYNAMIC_TYPE_SSL);
XFREE(ssl->heap, heap, DYNAMIC_TYPE_SSL);
#ifdef WOLFSSL_HEAP_TEST
}
#endif
@@ -10890,20 +10889,6 @@ void FreeHandshakeResources(WOLFSSL* ssl)
void FreeSSL(WOLFSSL* ssl, void* heap)
{
WOLFSSL_CTX* ctx = ssl->ctx;
#ifdef WOLFSSL_STATIC_MEMORY
WOLFSSL_HEAP_HINT poolHint;
/* wolfSSL_ResourceFree() frees ssl->heap, so keep only its pool */
if (heap != NULL && heap == ssl->heap
#ifdef WOLFSSL_HEAP_TEST
&& heap != (void*)WOLFSSL_HEAP_TEST
#endif
) {
XMEMSET(&poolHint, 0, sizeof(poolHint));
poolHint.memory = ((WOLFSSL_HEAP_HINT*)heap)->memory;
heap = &poolHint;
}
#endif
wolfSSL_ResourceFree(ssl);
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Check(ssl, sizeof(*ssl));

View File

@@ -800,11 +800,15 @@ WOLFSSL* wolfSSL_new(WOLFSSL_CTX* ctx)
WOLFSSL_ABI
void wolfSSL_free(WOLFSSL* ssl)
{
void *heap = NULL;
WOLFSSL_ENTER("wolfSSL_free");
if (ssl) {
WOLFSSL_MSG_EX("Free SSL: %p", (wc_ptr_t)ssl);
FreeSSL(ssl, ssl->heap);
if (ssl->ctx != NULL) {
heap = ssl->ctx->heap;
}
FreeSSL(ssl, heap);
}
else {
WOLFSSL_MSG("Free SSL: wolfSSL_free already null");
@@ -8996,6 +9000,13 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
return NULL;
if (ssl->ctx == ctx)
return ssl->ctx;
#ifdef WOLFSSL_STATIC_MEMORY
/* the SSL and its heap hint are freed through ssl->ctx->heap */
if (ssl->ctx != NULL && ssl->ctx->heap != ctx->heap) {
WOLFSSL_MSG("Cannot switch to a CTX with a different heap");
return NULL;
}
#endif
/* suites, allocated and derived under the CTX mutex as this CTX may be
* shared with other threads. Done before taking a reference below so that

View File

@@ -38255,6 +38255,70 @@ static int test_wolfSSL_CTX_StaticMemory(void)
return EXPECT_RESULT();
}
/* An SSL may only switch to a CTX with the same static-memory heap. */
static int test_wolfSSL_set_SSL_CTX_static_heap(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFCRYPT_ONLY) && \
(defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && \
!defined(NO_WOLFSSL_CLIENT)
byte memA[TEST_TLS_STATIC_MEMSZ];
byte memB[TEST_TLS_STATIC_MEMSZ];
WOLFSSL_HEAP_HINT* heapA = NULL;
WOLFSSL_HEAP_HINT* heapB = NULL;
WOLFSSL_CTX* ctxA = NULL;
WOLFSSL_CTX* ctxA2 = NULL;
WOLFSSL_CTX* ctxB = NULL;
#ifndef WOLFSSL_NO_MALLOC
WOLFSSL_CTX* ctxNoHeap = NULL;
#endif
WOLFSSL* ssl = NULL;
ExpectIntEQ(wc_LoadStaticMemory(&heapA, memA, sizeof(memA), 0, 1), 0);
ExpectIntEQ(wc_LoadStaticMemory(&heapB, memB, sizeof(memB), 0, 1), 0);
ExpectNotNull(ctxA = wolfSSL_CTX_new_ex(wolfSSLv23_client_method_ex(heapA),
heapA));
ExpectNotNull(ctxA2 = wolfSSL_CTX_new_ex(
wolfSSLv23_client_method_ex(heapA), heapA));
ExpectNotNull(ctxB = wolfSSL_CTX_new_ex(wolfSSLv23_client_method_ex(heapB),
heapB));
ExpectNotNull(ssl = wolfSSL_new(ctxA));
ExpectNull(wolfSSL_set_SSL_CTX(ssl, ctxB));
ExpectPtrEq(wolfSSL_get_SSL_CTX(ssl), ctxA);
wolfSSL_free(ssl);
ssl = NULL;
#ifndef WOLFSSL_NO_MALLOC
ExpectNotNull(ctxNoHeap = wolfSSL_CTX_new(wolfSSLv23_client_method()));
ExpectNotNull(ssl = wolfSSL_new(ctxA));
ExpectNull(wolfSSL_set_SSL_CTX(ssl, ctxNoHeap));
ExpectPtrEq(wolfSSL_get_SSL_CTX(ssl), ctxA);
wolfSSL_free(ssl);
ssl = NULL;
ExpectNotNull(ssl = wolfSSL_new(ctxNoHeap));
ExpectNull(wolfSSL_set_SSL_CTX(ssl, ctxA));
ExpectPtrEq(wolfSSL_get_SSL_CTX(ssl), ctxNoHeap);
wolfSSL_free(ssl);
ssl = NULL;
wolfSSL_CTX_free(ctxNoHeap);
#endif
ExpectNotNull(ssl = wolfSSL_new(ctxA));
ExpectPtrEq(wolfSSL_set_SSL_CTX(ssl, ctxA2), ctxA2);
ExpectPtrEq(wolfSSL_get_SSL_CTX(ssl), ctxA2);
wolfSSL_free(ssl);
wolfSSL_CTX_free(ctxA);
wolfSSL_CTX_free(ctxA2);
wolfSSL_CTX_free(ctxB);
wc_UnloadStaticMemory(heapA);
wc_UnloadStaticMemory(heapB);
#endif
return EXPECT_RESULT();
}
static int test_openssl_FIPS_drbg(void)
{
EXPECT_DECLS;
@@ -45798,6 +45862,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wc_CryptoCb_Hmac_Find),
/* Can't memory test as client/server hangs. */
TEST_DECL(test_wolfSSL_CTX_StaticMemory),
TEST_DECL(test_wolfSSL_set_SSL_CTX_static_heap),
#if !defined(NO_FILESYSTEM) && \
defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)