From 845a3a93b552d563be246423e183d5d83bac1f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Mon, 29 Jun 2026 10:11:34 +0200 Subject: [PATCH] F-6345 - Reject oversized length in memory BIO write wolfSSL_BIO_write rejected negative lengths but allowed a large positive length through to wolfSSL_BIO_MEMORY_write. On a fresh buffer an INT_MAX length overflowed the 4/3 buffer growth calculation, so the grow reported success with a short allocation and the following copy read far past the small source buffer. Add an upper bound check that rejects lengths large enough to overflow the growth math before any allocation or copy, and add a regression test that drives a huge length through the public BIO_write entry point. --- src/bio.c | 10 ++++++++++ tests/api/test_ossl_bio.c | 33 +++++++++++++++++++++++++++++++++ tests/api/test_ossl_bio.h | 2 ++ 3 files changed, 45 insertions(+) diff --git a/src/bio.c b/src/bio.c index b9dfe6b7dd..9d94144f57 100644 --- a/src/bio.c +++ b/src/bio.c @@ -631,6 +631,16 @@ static int wolfSSL_BIO_MEMORY_write(WOLFSSL_BIO* bio, const void* data, if (len <= 0) return 0; /* Nothing to write */ + /* Reject sizes that would overflow the buffer growth calculation, which + * rounds the requested size up to the next multiple of 4/3 via + * (size + 3) / 3 * 4. The extra rounding slack means the safe ceiling is + * one below (INT_MAX / 4) * 3. Without this an oversized length grows a + * short buffer and copies past the source. */ + if (len > ((INT_MAX / 4) * 3) - 1 - bio->wrSz) { + WOLFSSL_MSG("write length too large"); + return WOLFSSL_BIO_ERROR; + } + if (wolfSSL_BUF_MEM_grow_ex(bio->mem_buf, ((size_t)bio->wrSz) + ((size_t)len), 0) == 0) { WOLFSSL_MSG("Error growing memory area"); diff --git a/tests/api/test_ossl_bio.c b/tests/api/test_ossl_bio.c index b111fd4468..6223ee8f93 100644 --- a/tests/api/test_ossl_bio.c +++ b/tests/api/test_ossl_bio.c @@ -1019,6 +1019,39 @@ int test_wolfSSL_BIO_read_negative_len(void) return EXPECT_RESULT(); } +/* A length larger than the source buffer must never reach XMEMCPY in the + * memory-BIO write path. A huge positive length on a fresh buffer would + * otherwise overflow the buffer growth calculation, allocate a short + * destination, and copy far past the small source. Verify such a length is + * rejected with an error, nothing is buffered, and normal writes still work. */ +int test_wolfSSL_BIO_write_large_len(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) + BIO* bio = NULL; + char msg[] = "large length test"; + int msgLen = (int)XSTRLEN(msg); + char out[64]; + + ExpectNotNull(bio = BIO_new(BIO_s_mem())); + + /* Oversized length on a fresh buffer: must be rejected with an error, not + * a wild copy from the small source buffer. */ + ExpectIntLT(BIO_write(bio, msg, (int)0x7FFFFFFF), 0); + /* Nothing should have been buffered. */ + ExpectIntEQ(BIO_pending(bio), 0); + + /* A normal write then read still returns the intact message. */ + ExpectIntEQ(BIO_write(bio, msg, msgLen), msgLen); + XMEMSET(out, 0, sizeof(out)); + ExpectIntEQ(BIO_read(bio, out, (int)sizeof(out)), msgLen); + ExpectIntEQ(XMEMCMP(out, msg, msgLen), 0); + + BIO_free(bio); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_BIO_printf(void) { diff --git a/tests/api/test_ossl_bio.h b/tests/api/test_ossl_bio.h index acf13fb776..7aac4f4add 100644 --- a/tests/api/test_ossl_bio.h +++ b/tests/api/test_ossl_bio.h @@ -36,6 +36,7 @@ int test_wolfSSL_BIO_s_null(void); int test_wolfSSL_BIO_accept(void); int test_wolfSSL_BIO_write(void); int test_wolfSSL_BIO_read_negative_len(void); +int test_wolfSSL_BIO_write_large_len(void); int test_wolfSSL_BIO_printf(void); int test_wolfSSL_BIO_f_md(void); int test_wolfSSL_BIO_up_ref(void); @@ -57,6 +58,7 @@ int test_wolfSSL_BIO_get_init(void); TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_s_null), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_write), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_read_negative_len), \ + TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_write_large_len), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_printf), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_f_md), \ TEST_DECL_GROUP("ossl_bio", test_wolfSSL_BIO_up_ref), \