]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4304: js_norm: abort PDF norm on syntax failure
authorDanylo Kyrylov -X (dkyrylov - SOFTSERVE INC at Cisco) <dkyrylov@cisco.com>
Fri, 24 May 2024 08:31:12 +0000 (08:31 +0000)
committerOleksii Shumeiko -X (oshumeik - SOFTSERVE INC at Cisco) <oshumeik@cisco.com>
Fri, 24 May 2024 08:31:12 +0000 (08:31 +0000)
Merge in SNORT/snort3 from ~DKYRYLOV/snort3:pdf_no_inf_tokens to master

Squashed commit of the following:

commit abc86c1343f5f3b7ce2675b2742306e3c29289e9
Author: dkyrylov <dkyrylov@cisco.com>
Date:   Tue Apr 30 18:02:22 2024 +0300

    js_norm: stop PDF processing on syntax error

        Stop processing if buffer size is extended
        to fit a token over 16k in length;
        Abort further normalization after PDF
        tokenizer failure;
        Process last remaining JavaScript in
        PDU up to normalization failure.

src/js_norm/js_norm.cc
src/js_norm/js_pdf_norm.cc
src/js_norm/pdf_tokenizer.h
src/js_norm/pdf_tokenizer.l
src/js_norm/test/pdf_tokenizer_test.cc

index 07ed4983a7d31d3612b0c35af5a0f76dc90d92e8..38da1e92d3074d15c3c2517aec46ed52520c704b 100644 (file)
@@ -130,7 +130,7 @@ void JSNorm::normalize(const void* in_data, size_t in_len, const void*& data, si
         JSNormModule::increment_peg_counts(PEG_BYTES, next - src_ptr);
         src_ptr = next;
 
-        alive = post_proc(ret);
+        alive = alive and post_proc(ret);
     }
 
     if (jsn_ctx != nullptr)
index 0147bb124b6014d9e4e06eb00da6f34599cad404..ad3d8df79420fd1cb2ffcf2064e3762d03f663f8 100644 (file)
@@ -60,7 +60,7 @@ bool PDFJSNorm::pre_proc()
     {
         trace_logf(2, js_trace, TRACE_PROC, DetectionEngine::get_current_packet(),
             "pdf processing failed: %d\n", (int)r);
-        return false;
+        alive = false;
     }
 
     src_ptr = (const uint8_t*)buf_pdf_out.data();
index b520c64b25c97307aa2873a470b402947348f15f..4aca27c914e554a2a3533deb9c368a6089bd361c 100644 (file)
@@ -41,6 +41,7 @@ public:
         INCOMPLETE_ARRAY_IN_DICTIONARY,
         STREAM_NO_LENGTH,
         UNEXPECTED_SYMBOL,
+        TOKEN_TOO_LONG,
         MAX
     };
 
index 7be9fd698d0cfc787d171ba2afaee5f87444ff01..68bae284728606341f8d4ad663abde779c7efb51 100644 (file)
@@ -79,7 +79,9 @@ GRP_DELIMITER      [\(\)\<\>\[\]\{\}\/\%]
 GRP_REGULAR        [^\x00\x09\x0a\x0c\x0d\x20\(\)\<\>\[\]\{\}\/\%]
 
 /* 7.2.3 Comments */
-COMMENT            %{GRP_NOT_NEWLINE}*{EOL_MARKER}
+COMMENT_START      %
+COMMENT_CONTENT    {GRP_NOT_NEWLINE}{1,16}
+COMMENT_END        {EOL_MARKER}
 
 /* 7.3.2 Boolean Objects */
 OBJ_BOOLEAN        true|false
@@ -145,17 +147,20 @@ OBJ_REFERENCE        {OBJ_INT_NUM}{GRP_WHITESPACE}+{OBJ_INT_NUM}{GRP_WHITESPACE}
 SKIP              [^[:digit:]%]{1,16}|.
 WHITESPACE        {GRP_WHITESPACE}{1,16}
 
-/* Start conditions: INITIAL or inside dictionary, literal string, hexadecimal string, stream */
+/* Start conditions: structures: comment, indirect object, dictionary or array */
+%x comment
 %x indobj
-%x stream
 %x dictnr
+
+/* Start conditions: literals: regular, hexadecimal, stream */
 %x litstr
 %x hexstr
+%x stream
 %x jslstr
 %x jshstr
 %x jsstream
 
-/* Start conditions: UTF-16BE BOM, UTF-16BE literal string, UTF-16BE hexadecimal string, UTF-16BE stream */
+/* Start conditions: UTF-16BE: BOM, hex BOM, regular, hexadecimal, stream */
 %x u16
 %x u16hex
 %x jsstru16
@@ -164,11 +169,12 @@ WHITESPACE        {GRP_WHITESPACE}{1,16}
 
 %%
 
-{SKIP}                                            { }
-{COMMENT}                                         { }
+
+<INITIAL,indobj,dictnr>{COMMENT_START}            { PUSH(comment); }
+<comment>{COMMENT_CONTENT}                        { }
+<comment>{COMMENT_END}                            { POP(); }
 
 <INITIAL>{INDIRECT_OBJ_OPEN}                      { PUSH(indobj); h_ind_obj_open(); }
-<indobj>{COMMENT}                                 { }
 <indobj>{WHITESPACE}                              { }
 <indobj>{INDIRECT_OBJ_CLOSE}                      { POP(); h_ind_obj_close(); }
 
@@ -183,7 +189,6 @@ WHITESPACE        {GRP_WHITESPACE}{1,16}
 <dictnr>{OBJ_DICT_OPEN}                           { PUSH(dictnr); EXEC(h_dict_open()) }
 <indobj>{OBJ_DICT_OPEN}                           { PUSH(dictnr); EXEC(h_dict_open()) }
 <dictnr>{OBJ_DICT_CLOSE}                          { POP(); EXEC(h_dict_close()) }
-<dictnr>{COMMENT}                                 { }
 <dictnr>{WHITESPACE}                              { }
 <dictnr>{OBJ_REFERENCE}                           { EXEC(h_dict_other()) h_ref(); }
 <dictnr>{OBJ_BOOLEAN}                             { EXEC(h_dict_other()) }
@@ -238,6 +243,7 @@ WHITESPACE        {GRP_WHITESPACE}{1,16}
 
 <*><<EOF>>                                        { return PDFRet::EOS; }
 
+{SKIP}                                            { }
 <*>.|\n                                           { return PDFRet::UNEXPECTED_SYMBOL; }
 
 %%
@@ -619,6 +625,16 @@ PDFTokenizer::~PDFTokenizer()
 
 PDFTokenizer::PDFRet PDFTokenizer::process()
 {
-    auto r = yylex();
-    return static_cast<PDFTokenizer::PDFRet>(r);
+    auto r = static_cast<PDFTokenizer::PDFRet>(yylex());
+
+    if (!yy_buffer_stack or !YY_CURRENT_BUFFER_LVALUE)
+        return r;
+
+    if (YY_CURRENT_BUFFER_LVALUE->yy_buf_size > YY_BUF_SIZE)
+        r = PDFTokenizer::TOKEN_TOO_LONG;
+
+    if (r != PDFTokenizer::EOS)
+        yy_flush_buffer(YY_CURRENT_BUFFER);
+
+    return r;
 }
index fd1df1cf32e8f67c26fae974e81693351bd79900..f6b53b874bd4cf0a9db2fc5149647f2da2e6eb9c 100644 (file)
@@ -279,6 +279,15 @@ TEST_CASE("basic", "[PDFTokenizer]")
             "",  PDFTokenizer::PDFRet::INCOMPLETE_ARRAY_IN_DICTIONARY
         );
     }
+    SECTION("token too long")
+    {
+        test_pdf_proc(
+            "1"s + std::string(16 * 1024,' ') + " 0 obj"
+            "<< >>"
+            "endobj"s,
+            "",  PDFTokenizer::PDFRet::TOKEN_TOO_LONG
+        );
+    }
 }
 
 TEST_CASE("JS location", "[PDFTokenizer]")