mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-09 17:30:51 +02:00
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.
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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), \
|
||||
|
||||
Reference in New Issue
Block a user