]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2573 in SNORT/snort3 from ~MDAGON/snort3:h2_inject_big to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Tue, 27 Oct 2020 13:13:31 +0000 (13:13 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Tue, 27 Oct 2020 13:13:31 +0000 (13:13 +0000)
Squashed commit of the following:

commit 6cbee883ef13974c2fa3daf7794fda64fc743edb
Author: mdagon <mdagon@cisco.com>
Date:   Tue Sep 22 15:12:36 2020 -0400

    payload_injector: support page > 16k

src/payload_injector/payload_injector_module.cc
src/payload_injector/payload_injector_module.h
src/payload_injector/payload_injector_translate_page.cc
src/payload_injector/test/payload_injector_test.cc
src/payload_injector/test/payload_injector_translate_test.cc

index b33a69075280259820bd1c25fc437c67b068752d..0187242ef5bc53660a313d38e13718a51e34c16c 100644 (file)
@@ -59,7 +59,6 @@ static const std::map <InjectionReturnStatus, const char*> InjectionErrorToStrin
     { ERR_HTTP2_MID_FRAME, "HTTP/2 - attempt to inject mid frame. Currently not supported." },
     { ERR_TRANSLATED_HDRS_SIZE,
       "HTTP/2 translated header size is bigger than expected. Update max size." },
-    { ERR_HTTP2_BODY_SIZE, "HTTP/2 body is > 16k. Currently not supported." },
     { ERR_HTTP2_EVEN_STREAM_ID, "HTTP/2 - injection to server initiated stream" },
     { ERR_PKT_FROM_SERVER, "Packet is from server" }
 };
index 466319213940a0023f9063e065e93a9554e560bf..18b225879e4480a64a1851210a07c853cc233d21 100644 (file)
@@ -49,9 +49,8 @@ enum InjectionReturnStatus : int8_t
     ERR_PAGE_TRANSLATION = -5,
     ERR_HTTP2_MID_FRAME = -6,
     ERR_TRANSLATED_HDRS_SIZE = -7,
-    ERR_HTTP2_BODY_SIZE = -8,
-    ERR_HTTP2_EVEN_STREAM_ID = -9,
-    ERR_PKT_FROM_SERVER = -10,  
+    ERR_HTTP2_EVEN_STREAM_ID = -8,
+    ERR_PKT_FROM_SERVER = -9,
     // Update InjectionErrorToString when adding/removing error codes
 };
 
index d85dbaab82367b903e1bd716e97ebc2f02e91b32..aaeaeff4f96e1f82e4cf82bc3255089c6b471d4a 100644 (file)
@@ -260,21 +260,29 @@ InjectionReturnStatus PayloadInjectorModule::get_http2_payload(InjectionControl
     if (status != INJECTION_SUCCESS)
         return status;
 
-    const uint32_t body_len = control.http_page_len - body_offset;
-    // FIXIT-E support larger body size
-    if (body_len > 1<<14)
-        return ERR_HTTP2_BODY_SIZE;
-
-    payload_len = 2*FRAME_HEADER_LENGTH + hdr_len + body_len;
+    uint32_t body_len = control.http_page_len - body_offset;
+    uint32_t num_data_frames = body_len / (1<<14);
+    if (body_len % (1<<14) != 0)
+        num_data_frames++;
+    payload_len = FRAME_HEADER_LENGTH*(num_data_frames + 1) + hdr_len + body_len;
     http2_payload = (uint8_t*)snort_alloc(payload_len);
 
     uint8_t* http2_payload_cur = http2_payload;
     write_frame_hdr(http2_payload_cur, hdr_len, FT_HEADERS, END_HEADERS, control.stream_id);
     memcpy(http2_payload_cur, http2_hdr, hdr_len);
     http2_payload_cur += hdr_len;
-    write_frame_hdr(http2_payload_cur, body_len, FT_DATA, END_STREAM, control.stream_id);
-    memcpy(http2_payload_cur, control.http_page + body_offset, body_len);
-
+    const uint8_t* http_body_cur = control.http_page + body_offset;
+    while (body_len)
+    {
+        const uint32_t cur_len = (body_len > 1<<14) ? 1<<14 : body_len;
+        body_len -= cur_len;
+        const uint8_t flags = (body_len == 0) ? END_STREAM : 0;
+        write_frame_hdr(http2_payload_cur, cur_len, FT_DATA, flags, control.stream_id);
+        memcpy(http2_payload_cur, http_body_cur, cur_len);
+        http2_payload_cur += cur_len;
+        http_body_cur += cur_len;
+    }
+    assert((http2_payload_cur - http2_payload) == payload_len);
     return INJECTION_SUCCESS;
 }
 
index 12a8abebe326f95b88d55d03f4bfc96543e85bbe..6e0c1fccf1a88be38c98597c0688233d8ec37a59 100644 (file)
@@ -331,6 +331,18 @@ TEST(payload_injector_test, http2_pkt_from_srvr)
     delete flow.gadget;
 }
 
+TEST(payload_injector_test, flow_is_null)
+{
+    mod.set_configured(true);
+    Packet p(false);
+    p.packet_flags = PKT_STREAM_EST;
+    InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+    CHECK(counts->http_injects == 0);
+    CHECK(status == ERR_UNIDENTIFIED_PROTOCOL);
+    const char* err_string = mod.get_err_string(status);
+    CHECK(strcmp(err_string, "Unidentified protocol") == 0);
+}
+
 TEST_GROUP(payload_injector_translate_err_test)
 {
     PayloadInjectorModule mod;
@@ -389,17 +401,6 @@ TEST(payload_injector_translate_err_test, http2_hdrs_size)
         "HTTP/2 translated header size is bigger than expected. Update max size.") == 0);
 }
 
-TEST(payload_injector_translate_err_test, http2_body_size)
-{
-    Packet p(false);
-    p.packet_flags = PKT_STREAM_EST;
-    p.flow = &flow;
-    translation_status = ERR_HTTP2_BODY_SIZE;
-    status = mod.inject_http_payload(&p, control);
-    const char* err_string = mod.get_err_string(status);
-    CHECK(strcmp(err_string, "HTTP/2 body is > 16k. Currently not supported.") == 0);
-}
-
 int main(int argc, char** argv)
 {
     return CommandLineTestRunner::RunAllTests(argc, argv);
index b620068897251bc0fd5e59fe22f09d60c5b660b4..d0ea288ba38232c3ca43d2ad0e894dc4fb9eb732 100644 (file)
@@ -584,19 +584,51 @@ TEST(payload_injector_translate_test, http2_hdr_too_big5)
     CHECK(status == ERR_TRANSLATED_HDRS_SIZE);
 }
 
-TEST(payload_injector_translate_test, payload_body_larger_than_max)
+TEST(payload_injector_translate_test, payload_body_is_exactly_1_data_frame)
 {
-    static const uint32_t size = (1<<14) + 1 + strlen("HTTP/1.1 403 Forbidden\r\n\r\n");
+    static const uint32_t size = (1<<14) + strlen("HTTP/1.1 200 OK\r\n\r\n");
     uint8_t http_page[size];
     memset(http_page,'a',size);
-    memcpy(http_page,"HTTP/1.1 403 Forbidden\r\n\r\n", strlen("HTTP/1.1 403 Forbidden\r\n\r\n"));
+    memcpy(http_page,"HTTP/1.1 200 OK\r\n\r\n", strlen("HTTP/1.1 200 OK\r\n\r\n"));
 
     InjectionControl control;
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
     status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len);
-    CHECK(status == ERR_HTTP2_BODY_SIZE);
+    CHECK(status == INJECTION_SUCCESS);
+    // Headers frame header + status ok + data frame header
+    uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 1, 0, 0, 0, 1 };
+    CHECK(memcmp(http2_payload, out, sizeof(out))==0);
+    // Data frame == http body
+    CHECK(memcmp(http2_payload + sizeof(out), http_page + strlen("HTTP/1.1 200 OK\r\n\r\n"),
+        1<<14)==0);
+    snort_free(http2_payload);
+}
+
+TEST(payload_injector_translate_test, payload_body_is_data_frame_plus_1)
+{
+    static const uint32_t size = (1<<14) + 1 + strlen("HTTP/1.1 200 OK\r\n\r\n");
+    uint8_t http_page[size];
+    memset(http_page,'a',size);
+    memcpy(http_page,"HTTP/1.1 200 OK\r\n\r\n", strlen("HTTP/1.1 200 OK\r\n\r\n"));
+
+    InjectionControl control;
+    control.stream_id = 1;
+    control.http_page = http_page;
+    control.http_page_len = size;
+    status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len);
+    CHECK(status == INJECTION_SUCCESS);
+    // Headers frame header + status ok + data frame header
+    uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 0, 0, 0, 0, 1 };
+    CHECK(memcmp(http2_payload, out, sizeof(out))==0);
+    // First data frame
+    CHECK(memcmp(http2_payload + sizeof(out), http_page + strlen("HTTP/1.1 200 OK\r\n\r\n"),
+        1<<14)==0);
+    // Second data frame header + 1 last byte of body
+    uint8_t out2[] = { 0, 0, 1, 0, 1, 0, 0, 0, 1, 'a' };
+    CHECK(memcmp(http2_payload + sizeof(out) + (1<<14), out2, sizeof(out2))==0);
+    snort_free(http2_payload);
 }
 
 TEST(payload_injector_translate_test, http_page_is_nullptr)
@@ -621,27 +653,26 @@ TEST(payload_injector_translate_test, http_page_is_0_length)
 
 TEST(payload_injector_translate_test, 7_bit_int_min_max)
 {
-   uint8_t out[6];
-   uint32_t out_free_space = sizeof(out);
-
-   // Translate 0
-   uint8_t* cur = out;
-   InjectionReturnStatus status = write_7_bit_prefix_int(0, cur, out_free_space);
-   uint8_t expected_out[] = {0};
-   CHECK(status == INJECTION_SUCCESS);
-   CHECK(out_free_space == 5);
-   CHECK(memcmp(out, expected_out, 1) == 0);
-
-   // Translate max uint_32
-   cur = out;
-   out_free_space = sizeof(out);
-   status = write_7_bit_prefix_int(UINT32_MAX, cur, out_free_space);
-   uint8_t expected_out2[] = {0x7f, 0x80, 0xff, 0xff, 0xff, 0xf};
-   CHECK(status == INJECTION_SUCCESS);
-   CHECK(out_free_space == 0);
-   CHECK(memcmp(out, expected_out2, 6) == 0);
-}
+    uint8_t out[6];
+    uint32_t out_free_space = sizeof(out);
 
+    // Translate 0
+    uint8_t* cur = out;
+    InjectionReturnStatus status = write_7_bit_prefix_int(0, cur, out_free_space);
+    uint8_t expected_out[] = { 0 };
+    CHECK(status == INJECTION_SUCCESS);
+    CHECK(out_free_space == 5);
+    CHECK(memcmp(out, expected_out, 1) == 0);
+
+    // Translate max uint_32
+    cur = out;
+    out_free_space = sizeof(out);
+    status = write_7_bit_prefix_int(UINT32_MAX, cur, out_free_space);
+    uint8_t expected_out2[] = { 0x7f, 0x80, 0xff, 0xff, 0xff, 0xf };
+    CHECK(status == INJECTION_SUCCESS);
+    CHECK(out_free_space == 0);
+    CHECK(memcmp(out, expected_out2, 6) == 0);
+}
 
 int main(int argc, char** argv)
 {