]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2774 in SNORT/snort3 from ~MMATIRKO/snort3:funky_flush to master
authorMasud Hasan (mashasan) <mashasan@cisco.com>
Fri, 5 Mar 2021 13:39:42 +0000 (13:39 +0000)
committerMasud Hasan (mashasan) <mashasan@cisco.com>
Fri, 5 Mar 2021 13:39:42 +0000 (13:39 +0000)
Squashed commit of the following:

commit 12979dc9a9035a732d7be73a2a1b0d42000c97b8
Author: russ <rucombs@cisco.com>
Date:   Mon Mar 1 10:21:38 2021 -0500

    stream_tcp: Ensure flows aren't pruned while processing a PDU

    Externally triggered flushes require a new context if a packet is not
    already in play. All external flushes require a new packet.

src/detection/detection_engine.cc
src/flow/flow.h
src/protocols/packet.h
src/protocols/packet_manager.cc
src/stream/stream.cc
src/stream/tcp/tcp_reassembler.cc
src/stream/tcp/tcp_reassembler.h
src/stream/tcp/tcp_reassemblers.h

index 0a4a0c9da1c6731fd1e03a39b3f672561a671526..13094254d1cf3f36010776fa3e53249731d39d57 100644 (file)
@@ -196,6 +196,9 @@ Packet* DetectionEngine::set_next_packet(Packet* parent)
         shutdown_active.reset();
     }
 
+    if ( parent )
+        p->packet_flags |= PKT_HAS_PARENT;
+
     p->reset();
     return p;
 }
@@ -233,7 +236,10 @@ void DetectionEngine::finish_inspect(Packet* p, bool inspected)
     // clear closed sessions here after inspection since non-stream
     // inspectors may depend on flow information
     // this also handles block pending state
-    Stream::check_flow_closed(p);
+    // must only be done for terminal packets to avoid yoinking stream_tcp state
+    // while processing a PDU
+    if ( !p->has_parent() )
+        Stream::check_flow_closed(p);
 
     if ( inspected and !p->context->next() )
         InspectorManager::clear(p);
index 410b41c4daf2e2af3a8acbbb16fb79d935f39028..c600d72ecfe0a13a6633be44589439962f310a8a 100644 (file)
@@ -96,6 +96,7 @@
 #define STREAM_STATE_UNREACH           0x0100
 #define STREAM_STATE_CLOSED            0x0200
 #define STREAM_STATE_BLOCK_PENDING     0x0400
+#define STREAM_STATE_RELEASING         0x0800
 
 class BitOp;
 class Session;
index 5f42bdddf002fca772876f75666fbb7d7436c826..33c4dbbb912b1f64a8400ba2b4aac6c920587f43 100644 (file)
@@ -80,7 +80,10 @@ class SFDAQInstance;
 #define PKT_RETRANSMIT       0x01000000  // packet is a re-transmitted pkt.
 #define PKT_RETRY            0x02000000  /* this packet is being re-evaluated from the internal retry queue */
 #define PKT_USE_DIRECT_INJECT 0x04000000  /* Use ioctl when injecting. */
-#define PKT_UNUSED_FLAGS     0xf8000000
+#define PKT_HAS_PARENT       0x08000000  /* derived pseudo packet from current wire packet */
+
+#define PKT_WAS_SET          0x10000000  /* derived pseudo packet (PDU) from current wire packet */
+#define PKT_UNUSED_FLAGS     0xE0000000
 
 #define PKT_TS_OFFLOADED        0x01
 
@@ -313,6 +316,12 @@ struct SO_PUBLIC Packet
     void clear_offloaded()
     { ts_packet_flags &= (~PKT_TS_OFFLOADED); }
 
+    bool has_parent() const
+    { return (packet_flags & PKT_HAS_PARENT) != 0; }
+
+    bool was_set() const
+    { return (packet_flags & PKT_WAS_SET) != 0; }
+
     bool is_detection_enabled(bool to_server);
 
     bool is_inter_group_flow() const
index 843260338e52c75e044f281c3ae70862bba01979..8142f1aecf71c2e30eeae08fca78afac3d8d3f74 100644 (file)
@@ -660,10 +660,11 @@ int PacketManager::format_tcp(
     EncodeFlags, const Packet* p, Packet* c, PseudoPacketType type,
     const DAQ_PktHdr_t* phdr, uint32_t opaque)
 {
+    uint32_t cflags = c->packet_flags;
     c->reset();
     init_daq_pkthdr(p, c, phdr, opaque);
 
-    c->packet_flags |= PKT_PSEUDO;
+    c->packet_flags = cflags | PKT_PSEUDO;
     c->pseudo_type = type;
 
     // cooked packet gets same policy as raw
index 5e8ccfb7eb80e0f8137d51e59be309502630c643..72891fa875359026f07054cd74d9161755381f36 100644 (file)
@@ -195,9 +195,11 @@ void Stream::check_flow_closed(Packet* p)
 {
     Flow* flow = p->flow;
 
-    if ( !flow )
+    if ( !flow or (flow->session_state & STREAM_STATE_RELEASING) )
         return;
 
+    flow->session_state |= STREAM_STATE_RELEASING;
+
     if (flow->session_state & STREAM_STATE_CLOSED)
     {
         assert(flow_con);
@@ -227,6 +229,8 @@ void Stream::check_flow_closed(Packet* p)
         }
         flow->clear_session_state(STREAM_STATE_BLOCK_PENDING);
     }
+
+    flow->session_state &= ~STREAM_STATE_RELEASING;
 }
 
 int Stream::ignore_flow(
index 91118c9b3555acd9d11e3a82e2e589b1f3512636..b5c173cd037202a8066521a0158cbde51ad7ef47 100644 (file)
@@ -485,7 +485,8 @@ void TcpReassembler::prep_pdu(
 Packet* TcpReassembler::initialize_pdu(
     TcpReassemblerState& trs, Packet* p, uint32_t pkt_flags, struct timeval tv)
 {
-    Packet* pdu = DetectionEngine::set_next_packet(p);
+    // partial flushes already set the pdu for http_inspect splitter processing
+    Packet* pdu = p->was_set() ? p : DetectionEngine::set_next_packet(p);
 
     EncodeFlags enc_flags = 0;
     DAQ_PktHdr_t pkth;
@@ -496,6 +497,8 @@ Packet* TcpReassembler::initialize_pdu(
     pdu->context->pkth->ts = tv;
     pdu->dsize = 0;
     pdu->data = nullptr;
+    pdu->ip_proto_next = (IpProtocol)p->flow->ip_proto;
+
     return pdu;
 }
 
@@ -712,16 +715,10 @@ void TcpReassembler::final_flush(TcpReassemblerState& trs, Packet* p, uint32_t d
     trs.tracker->clear_tf_flags(TF_FORCE_FLUSH);
 }
 
-static Packet* set_packet(Flow* flow, uint32_t flags, bool c2s)
+static Packet* get_packet(Flow* flow, uint32_t flags, bool c2s)
 {
-    // if not in the context of a wire packet the flush initiator must have
-    // created a packet context by calling DetectionEngine::set_next_packet()
-    Packet* p = DetectionEngine::get_current_packet();
-    assert(p->pkth == p->context->pkth);
-
-    // FIXIT-M p points to a skeleton of a TCP PDU packet with no data and we now
-    // initialize the IPs/ports/flow and other fields accessed as we reassemble
-    // and flush the PDU. There are probably other Packet fields that should be set here...
+    Packet* p = DetectionEngine::set_next_packet();
+
     DAQ_PktHdr_t* ph = p->context->pkth;
     memset(ph, 0, sizeof(*ph));
     packet_gettimeofday(&ph->ts);
@@ -761,11 +758,6 @@ static Packet* set_packet(Flow* flow, uint32_t flags, bool c2s)
 void TcpReassembler::flush_queued_segments(
     TcpReassemblerState& trs, Flow* flow, bool clear, Packet* p)
 {
-    // if flushing outside the context of wire packet p will be null, initialize
-    // Packet object allocated for the current IpsContext
-    if ( !p )
-        p = set_packet(flow, trs.packet_dir, trs.server_side);
-
     bool pending = clear and paf_initialized(&trs.paf_state)
         and (!trs.tracker->get_splitter() || trs.tracker->get_splitter()->finish(flow) );
 
@@ -773,6 +765,22 @@ void TcpReassembler::flush_queued_segments(
         final_flush(trs, p, trs.packet_dir);
 }
 
+void TcpReassembler::flush_queued_segments(
+    TcpReassemblerState& trs, Flow* flow, bool clear, const Packet* p)
+{
+    Packet* pdu = get_packet(flow, trs.packet_dir, trs.server_side);
+
+    if ( p )
+        flush_queued_segments(trs, flow, clear, pdu);
+
+    else
+    {
+        // if we weren't given a packet, we must establish a context
+        DetectionEngine de;
+        flush_queued_segments(trs, flow, clear, pdu);
+    }
+}
+
 // this is for post-ack flushing
 uint32_t TcpReassembler::get_reverse_packet_dir(TcpReassemblerState&, const Packet* p)
 {
@@ -999,7 +1007,8 @@ int TcpReassembler::flush_on_data_policy(TcpReassemblerState& trs, Packet* p)
                     break;
 
                 flushed += flush_to_seq(trs, flush_amt, p, flags);
-            } while( trs.sos.seglist.head );
+            }
+            while ( trs.sos.seglist.head and !p->flow->is_inspection_disabled() );
 
             if ( !flags && trs.tracker->is_splitter_paf() )
             {
@@ -1063,7 +1072,8 @@ int TcpReassembler::flush_on_ack_policy(TcpReassemblerState& trs, Packet* p)
             // ideally we would purge just once after this loop but that throws off base
             if ( trs.sos.seglist.head )
                 purge_to_seq(trs, trs.sos.seglist_base_seq);
-        } while ( trs.sos.seglist.head );
+        }
+        while ( trs.sos.seglist.head and !p->flow->is_inspection_disabled() );
 
         if ( (trs.paf_state.paf == StreamSplitter::ABORT) && trs.tracker->is_splitter_paf() )
         {
@@ -1220,11 +1230,8 @@ void TcpReassembler::queue_packet_for_reassembly(
 
 uint32_t TcpReassembler::perform_partial_flush(TcpReassemblerState& trs, Flow* flow)
 {
-    // Call this first, to create a context before creating a packet:
-    DetectionEngine::set_next_packet();
-    DetectionEngine de;
+    Packet* p = get_packet(flow, (trs.packet_dir|PKT_WAS_SET), trs.server_side);
 
-    Packet* p = set_packet(flow, trs.packet_dir, trs.server_side);
     uint32_t result = perform_partial_flush(trs, p);
 
     // If the held_packet hasn't been released by perform_partial_flush(),
index 36abe19d411f4d96756dea0f48c8c0a77d49a688..b5c34344c68303541941ae04ef01508a1dfac875 100644 (file)
@@ -34,7 +34,7 @@ public:
     virtual int flush_stream(
         TcpReassemblerState&, snort::Packet* p, uint32_t dir, bool final_flush = false);
     virtual void flush_queued_segments(
-        TcpReassemblerState&, snort::Flow* flow, bool clear, snort::Packet* p = nullptr);
+        TcpReassemblerState&, snort::Flow* flow, bool clear, const snort::Packet* = nullptr);
     virtual bool is_segment_pending_flush(TcpReassemblerState&);
     virtual int flush_on_data_policy(TcpReassemblerState&, snort::Packet*);
     virtual int flush_on_ack_policy(TcpReassemblerState&, snort::Packet*);
@@ -65,6 +65,8 @@ protected:
     bool is_segment_fasttrack
         (TcpReassemblerState&, TcpSegmentNode* tail, const TcpSegmentDescriptor&);
     void show_rebuilt_packet(const TcpReassemblerState&, snort::Packet*);
+    void flush_queued_segments(
+        TcpReassemblerState&, snort::Flow* flow, bool clear, snort::Packet*);
     int flush_data_segments(TcpReassemblerState&, uint32_t flush_len, snort::Packet* pdu);
     void prep_pdu(
         TcpReassemblerState&, snort::Flow*, snort::Packet*, uint32_t pkt_flags, snort::Packet*);
index 0e529e094fbc510d57af8e140a00c7ba08034324..ceff0f093d1f2e475dc0c3eb3d16660e767243c5 100644 (file)
@@ -70,7 +70,7 @@ public:
     int flush_stream(snort::Packet* p, uint32_t dir, bool final_flush = false)
     { return reassembler->flush_stream(trs, p, dir, final_flush); }
 
-    void flush_queued_segments(snort::Flow* flow, bool clear, snort::Packet* p = nullptr)
+    void flush_queued_segments(snort::Flow* flow, bool clear, const snort::Packet* p = nullptr)
     { reassembler->flush_queued_segments(trs, flow, clear, p); }
 
     bool is_segment_pending_flush()