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), \