From 5a9e0a94af30f0642be5cf5f3b95d4c14ecbfe7f Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Fri, 4 Sep 2026 23:55:28 +0530 Subject: [PATCH] Validate stream receive buffer size Reject non-power-of-two stream receive buffer defaults before they reach receive buffer initialization, and cover core and public API validation paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/core/settings.c | 10 +++++++--- src/core/unittest/SettingsTest.cpp | 15 +++++++++++++++ src/test/lib/ApiTest.cpp | 8 ++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/core/settings.c b/src/core/settings.c index 5fbb57af80..09e514a399 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -426,6 +426,13 @@ QuicSettingApply( const QUIC_SETTINGS_INTERNAL* Source ) { + if (Source->IsSet.StreamRecvBufferDefault && + (!Destination->IsSet.StreamRecvBufferDefault || OverWrite) && + (!IS_POWER_OF_TWO(Source->StreamRecvBufferDefault) || + Source->StreamRecvBufferDefault < QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE)) { + return FALSE; + } + if (Source->IsSet.SendBufferingEnabled && (!Destination->IsSet.SendBufferingEnabled || OverWrite)) { Destination->SendBufferingEnabled = Source->SendBufferingEnabled; Destination->IsSet.SendBufferingEnabled = TRUE; @@ -577,9 +584,6 @@ QuicSettingApply( Destination->IsSet.StreamRecvWindowUnidiDefault = TRUE; } if (Source->IsSet.StreamRecvBufferDefault && (!Destination->IsSet.StreamRecvBufferDefault || OverWrite)) { - if (Source->StreamRecvBufferDefault < QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE) { - return FALSE; - } Destination->StreamRecvBufferDefault = Source->StreamRecvBufferDefault; Destination->IsSet.StreamRecvBufferDefault = TRUE; } diff --git a/src/core/unittest/SettingsTest.cpp b/src/core/unittest/SettingsTest.cpp index cec39a97cc..466c2a8da6 100644 --- a/src/core/unittest/SettingsTest.cpp +++ b/src/core/unittest/SettingsTest.cpp @@ -322,6 +322,21 @@ TEST(SettingsTest, StreamRecvWindowDefaultGetsOverridenByIndividualLimits) ASSERT_EQ(Destination.StreamRecvWindowUnidiDefault, Source.StreamRecvWindowUnidiDefault); } +TEST(SettingsTest, StreamRecvBufferDefaultRejectsInvalidSizesWithoutChanges) +{ + QUIC_SETTINGS_INTERNAL Source; + QUIC_SETTINGS_INTERNAL Destination; + CxPlatZeroMemory(&Source, sizeof(Source)); + CxPlatZeroMemory(&Destination, sizeof(Destination)); + QuicSettingsSetDefault(&Destination); + + Source.IsSet.StreamRecvBufferDefault = 1; + Source.StreamRecvBufferDefault = QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE + 1; + + ASSERT_FALSE(QuicSettingApply(&Destination, TRUE, TRUE, &Source)); + ASSERT_EQ(Destination.StreamRecvBufferDefault, QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE); +} + // TEST(SettingsTest, TestAllVersionSettingsFieldsGet) // { // QUIC_VERSION_SETTINGS Settings; diff --git a/src/test/lib/ApiTest.cpp b/src/test/lib/ApiTest.cpp index 13b1208dd9..c157266c74 100644 --- a/src/test/lib/ApiTest.cpp +++ b/src/test/lib/ApiTest.cpp @@ -2066,8 +2066,12 @@ void SettingApplyTests(HQUIC Handle, uint32_t Param, bool AllowMtuEcnChanges = t } { - struct TestSpec Spec[] = {{0, QUIC_STATUS_INVALID_PARAMETER}, - {QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE, QUIC_STATUS_SUCCESS}}; + struct TestSpec Spec[] = { + {0, QUIC_STATUS_INVALID_PARAMETER}, + {QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE + 1, QUIC_STATUS_INVALID_PARAMETER}, + {QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE, QUIC_STATUS_SUCCESS}, + {2 * QUIC_DEFAULT_STREAM_RECV_BUFFER_SIZE, QUIC_STATUS_SUCCESS} + }; QUIC_SETTINGS Settings{0}; Settings.IsSet.StreamRecvBufferDefault = TRUE; for (auto &Data: Spec) {