This is an automated email from the ASF dual-hosted git repository. eze pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new dc1a7e3c6f Reject reserved h2 to h3 frame types (#10113) dc1a7e3c6f is described below commit dc1a7e3c6f89a3b897054516ec63505fb8c84f9a Author: Evan Zelkowitz <e...@apache.org> AuthorDate: Fri Jul 28 14:38:00 2023 -0600 Reject reserved h2 to h3 frame types (#10113) --- proxy/http3/Http3DebugNames.cc | 6 ++ proxy/http3/Http3ProtocolEnforcer.cc | 11 ++- proxy/http3/test/test_Http3FrameDispatcher.cc | 130 ++++++++++++++++++++------ 3 files changed, 120 insertions(+), 27 deletions(-) diff --git a/proxy/http3/Http3DebugNames.cc b/proxy/http3/Http3DebugNames.cc index 9e3fbf9640..321c33b328 100644 --- a/proxy/http3/Http3DebugNames.cc +++ b/proxy/http3/Http3DebugNames.cc @@ -44,6 +44,12 @@ Http3DebugNames::frame_type(Http3FrameType type) return "GOAWAY"; case Http3FrameType::DUPLICATE_PUSH_ID: return "DUPLICATE_PUSH_ID"; + case Http3FrameType::X_RESERVED_1: + return "X_RESERVED_1"; + case Http3FrameType::X_RESERVED_2: + return "X_RESERVED_2"; + case Http3FrameType::X_RESERVED_3: + return "X_RESERVED_3"; case Http3FrameType::UNKNOWN: default: return "UNKNOWN"; diff --git a/proxy/http3/Http3ProtocolEnforcer.cc b/proxy/http3/Http3ProtocolEnforcer.cc index 9a90cda451..b2b64daad6 100644 --- a/proxy/http3/Http3ProtocolEnforcer.cc +++ b/proxy/http3/Http3ProtocolEnforcer.cc @@ -46,11 +46,20 @@ Http3ProtocolEnforcer::handle_frame(std::shared_ptr<const Http3Frame> frame, int } else if (frame_seq != 0 && f_type == Http3FrameType::SETTINGS) { error = std::make_unique<Http3ConnectionError>(Http3ErrorCode::H3_FRAME_UNEXPECTED, "only one SETTINGS frame is allowed per the control stream"); - } else if (f_type == Http3FrameType::DATA || f_type == Http3FrameType::HEADERS) { + } else if (f_type == Http3FrameType::DATA || f_type == Http3FrameType::HEADERS || f_type == Http3FrameType::X_RESERVED_1 || + f_type == Http3FrameType::X_RESERVED_2 || f_type == Http3FrameType::X_RESERVED_3) { std::string error_msg = Http3DebugNames::frame_type(f_type); error_msg.append(" frame is not allowed on control stream"); error = std::make_unique<Http3ConnectionError>(Http3ErrorCode::H3_FRAME_UNEXPECTED, error_msg.c_str()); } + } else { + if (f_type == Http3FrameType::X_RESERVED_1 || f_type == Http3FrameType::X_RESERVED_2 || + f_type == Http3FrameType::X_RESERVED_3) { + std::string error_msg = Http3DebugNames::frame_type(f_type); + error_msg.append(" frame is not allowed on any stream"); + error = std::make_unique<Http3ConnectionError>(Http3ErrorCode::H3_FRAME_UNEXPECTED, error_msg.c_str()); + } } + return error; } diff --git a/proxy/http3/test/test_Http3FrameDispatcher.cc b/proxy/http3/test/test_Http3FrameDispatcher.cc index 8ba980e202..0987e4e8dd 100644 --- a/proxy/http3/test/test_Http3FrameDispatcher.cc +++ b/proxy/http3/test/test_Http3FrameDispatcher.cc @@ -29,32 +29,37 @@ TEST_CASE("Http3FrameHandler dispatch", "[http3]") { - uint8_t input[] = {// 1st frame (HEADERS) - 0x01, 0x04, 0x11, 0x22, 0x33, 0x44, - // 2nd frame (DATA) - 0x00, 0x04, 0xaa, 0xbb, 0xcc, 0xdd, - // 3rd frame (incomplete) - 0xff}; - - Http3FrameDispatcher http3FrameDispatcher; - Http3MockFrameHandler handler; - http3FrameDispatcher.add_handler(&handler); - - MIOBuffer *buf = new_MIOBuffer(BUFFER_SIZE_INDEX_512); - IOBufferReader *reader = buf->alloc_reader(); - uint64_t nread = 0; - Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError()); - - buf->write(input, sizeof(input)); - - // Initial state - CHECK(handler.total_frame_received == 0); - CHECK(nread == 0); - - error = http3FrameDispatcher.on_read_ready(0, Http3StreamType::UNKNOWN, *reader, nread); - CHECK(error->app_error_code == Http3ErrorCode::H3_NO_ERROR); - CHECK(handler.total_frame_received == 1); - CHECK(nread == 12); + SECTION("Test good case") + { + uint8_t input[] = {// 1st frame (HEADERS) + 0x01, 0x04, 0x11, 0x22, 0x33, 0x44, + // 2nd frame (DATA) + 0x00, 0x04, 0xaa, 0xbb, 0xcc, 0xdd, + // 3rd frame (incomplete) + 0xff}; + + Http3FrameDispatcher http3FrameDispatcher; + Http3MockFrameHandler handler; + Http3ProtocolEnforcer enforcer; + http3FrameDispatcher.add_handler(&handler); + http3FrameDispatcher.add_handler(&enforcer); + + MIOBuffer *buf = new_MIOBuffer(BUFFER_SIZE_INDEX_512); + IOBufferReader *reader = buf->alloc_reader(); + uint64_t nread = 0; + Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError()); + + buf->write(input, sizeof(input)); + + // Initial state + CHECK(handler.total_frame_received == 0); + CHECK(nread == 0); + + error = http3FrameDispatcher.on_read_ready(0, Http3StreamType::UNKNOWN, *reader, nread); + CHECK(error->app_error_code == Http3ErrorCode::H3_NO_ERROR); + CHECK(handler.total_frame_received == 1); + CHECK(nread == 12); + } } TEST_CASE("control stream tests", "[http3]") @@ -219,6 +224,44 @@ TEST_CASE("control stream tests", "[http3]") CHECK(handler.total_frame_received == 1); CHECK(nread == sizeof(input)); } + + SECTION("RESERVED frame is not allowed on control stream") + { + uint8_t input[] = {0x04, // Type + 0x08, // Length + 0x06, // Identifier + 0x44, 0x00, // Value + 0x09, // Identifier + 0x0f, // Value + 0x4a, 0x0a, // Identifier + 0x00, // Value + 0x06, // Type + 0x04, // Length + 0x11, 0x22, 0x33, 0x44}; + + Http3FrameDispatcher http3FrameDispatcher; + Http3ProtocolEnforcer enforcer; + Http3MockFrameHandler handler; + + http3FrameDispatcher.add_handler(&enforcer); + http3FrameDispatcher.add_handler(&handler); + + MIOBuffer *buf = new_MIOBuffer(BUFFER_SIZE_INDEX_512); + IOBufferReader *reader = buf->alloc_reader(); + uint64_t nread = 0; + Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError()); + + buf->write(input, sizeof(input)); + + // Initial state + CHECK(handler.total_frame_received == 0); + CHECK(nread == 0); + + error = http3FrameDispatcher.on_read_ready(0, Http3StreamType::CONTROL, *reader, nread); + CHECK(error->app_error_code == Http3ErrorCode::H3_FRAME_UNEXPECTED); + CHECK(handler.total_frame_received == 1); + CHECK(nread == sizeof(input)); + } } TEST_CASE("ignore unknown frames", "[http3]") @@ -244,3 +287,38 @@ TEST_CASE("ignore unknown frames", "[http3]") CHECK(nread == 0); } } + +TEST_CASE("Reserved frame type not allowed", "[http3]") +{ + SECTION("Reject reserved frame type in non control stream") + { + uint8_t input[] = {// 1st frame (HEADERS) + 0x01, 0x04, 0x11, 0x22, 0x33, 0x44, + // 2nd frame (DATA) + 0x06, 0x04, 0xaa, 0xbb, 0xcc, 0xdd, + // 3rd frame (incomplete) + 0xff}; + + Http3FrameDispatcher http3FrameDispatcher; + Http3MockFrameHandler handler; + Http3ProtocolEnforcer enforcer; + http3FrameDispatcher.add_handler(&handler); + http3FrameDispatcher.add_handler(&enforcer); + + MIOBuffer *buf = new_MIOBuffer(BUFFER_SIZE_INDEX_512); + IOBufferReader *reader = buf->alloc_reader(); + uint64_t nread = 0; + Http3ErrorUPtr error = Http3ErrorUPtr(new Http3NoError()); + + buf->write(input, sizeof(input)); + + // Initial state + CHECK(handler.total_frame_received == 0); + CHECK(nread == 0); + + error = http3FrameDispatcher.on_read_ready(0, Http3StreamType::UNKNOWN, *reader, nread); + CHECK(error->app_error_code == Http3ErrorCode::H3_FRAME_UNEXPECTED); + CHECK(handler.total_frame_received == 0); + CHECK(nread == 12); + } +}