]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
af-packet: improve error handling
authorEric Leblond <eric@regit.org>
Mon, 8 Oct 2018 21:51:37 +0000 (23:51 +0200)
committerEric Leblond <eric@regit.org>
Fri, 2 Nov 2018 14:05:54 +0000 (15:05 +0100)
Stress condition in Suricata could lead to interface to disconnect
when it is not necessary. This patch updates the error handling
code to try to continue reading when such a case occurs.

src/source-af-packet.c

index 4b3c2f6f7a898aa4b3ffda21b0e519dfd1ab299a..a1c29afd74000536197f711eb955ca7850679163 100644 (file)
@@ -172,7 +172,8 @@ static SCMutex afpacket_bpf_set_filter_lock = SCMUTEX_INITIALIZER;
 enum {
     AFP_READ_OK,
     AFP_READ_FAILURE,
-    AFP_FAILURE,
+    /** Error during treatment by other functions of Suricata */
+    AFP_SURI_FAILURE,
     AFP_KERNEL_DROP,
 };
 
@@ -215,6 +216,7 @@ typedef struct AFPThreadVars_
     /* references to packet and drop counters */
     uint16_t capture_kernel_packets;
     uint16_t capture_kernel_drops;
+    uint16_t capture_errors;
 
     /* handle state */
     uint8_t afp_state;
@@ -594,7 +596,7 @@ static int AFPRead(AFPThreadVars *ptv)
 
     p = PacketGetFromQueueOrAlloc();
     if (p == NULL) {
-        SCReturnInt(AFP_FAILURE);
+        SCReturnInt(AFP_SURI_FAILURE);
     }
     PKT_SET_SRC(p, PKT_SRC_WIRE);
 
@@ -620,7 +622,7 @@ static int AFPRead(AFPThreadVars *ptv)
     SET_PKT_LEN(p, caplen + offset);
     if (PacketCopyData(p, ptv->data, GET_PKT_LEN(p)) == -1) {
         TmqhOutputPacketpool(ptv->tv, p);
-        SCReturnInt(AFP_FAILURE);
+        SCReturnInt(AFP_SURI_FAILURE);
     }
     SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)",
                GET_PKT_LEN(p), p, GET_PKT_DATA(p));
@@ -660,7 +662,7 @@ static int AFPRead(AFPThreadVars *ptv)
 
     if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
         TmqhOutputPacketpool(ptv->tv, p);
-        SCReturnInt(AFP_FAILURE);
+        SCReturnInt(AFP_SURI_FAILURE);
     }
     SCReturnInt(AFP_READ_OK);
 }
@@ -824,8 +826,10 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
 
         /* Read packet from ring */
         h.raw = (((union thdr **)ptv->ring_v2)[ptv->frame_offset]);
-        if (h.raw == NULL) {
-            SCReturnInt(AFP_FAILURE);
+        if (unlikely(h.raw == NULL)) {
+            /* Impossible we reach this point in normal condition, so trigger
+             * a failure in reading */
+            SCReturnInt(AFP_READ_FAILURE);
         }
 
         if ((! h.h2->tp_status) || (h.h2->tp_status & TP_STATUS_USER_BUSY)) {
@@ -863,7 +867,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
 
         p = PacketGetFromQueueOrAlloc();
         if (p == NULL) {
-            SCReturnInt(AFP_FAILURE);
+            SCReturnInt(AFP_SURI_FAILURE);
         }
         PKT_SET_SRC(p, PKT_SRC_WIRE);
 
@@ -892,7 +896,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
         if (ptv->flags & AFP_ZERO_COPY) {
             if (PacketSetData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) {
                 TmqhOutputPacketpool(ptv->tv, p);
-                SCReturnInt(AFP_FAILURE);
+                SCReturnInt(AFP_SURI_FAILURE);
             } else {
                 p->afp_v.relptr = h.raw;
                 p->ReleasePacket = AFPReleasePacket;
@@ -908,8 +912,15 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
             }
         } else {
             if (PacketCopyData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) {
+                /* As we can possibly fail to copy the data due to invalid data, let's
+                 * skip this packet and switch to the next one.
+                 */
+                h.h2->tp_status = TP_STATUS_KERNEL;
+                if (++ptv->frame_offset >= ptv->req.tp_frame_nr) {
+                    ptv->frame_offset = 0;
+                }
                 TmqhOutputPacketpool(ptv->tv, p);
-                SCReturnInt(AFP_FAILURE);
+                SCReturnInt(AFP_SURI_FAILURE);
             }
         }
         /* Timestamp */
@@ -951,7 +962,7 @@ static int AFPReadFromRing(AFPThreadVars *ptv)
                 ptv->frame_offset = 0;
             }
             TmqhOutputPacketpool(ptv->tv, p);
-            SCReturnInt(AFP_FAILURE);
+            SCReturnInt(AFP_SURI_FAILURE);
         }
 
 next_frame:
@@ -975,7 +986,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
 {
     Packet *p = PacketGetFromQueueOrAlloc();
     if (p == NULL) {
-        SCReturnInt(AFP_FAILURE);
+        SCReturnInt(AFP_SURI_FAILURE);
     }
     PKT_SET_SRC(p, PKT_SRC_WIRE);
 
@@ -993,7 +1004,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
     if (ptv->flags & AFP_ZERO_COPY) {
         if (PacketSetData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) {
             TmqhOutputPacketpool(ptv->tv, p);
-            SCReturnInt(AFP_FAILURE);
+            SCReturnInt(AFP_SURI_FAILURE);
         }
         p->afp_v.relptr = ppd;
         p->ReleasePacket = AFPReleasePacketV3;
@@ -1009,7 +1020,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
     } else {
         if (PacketCopyData(p, (unsigned char*)ppd + ppd->tp_mac, ppd->tp_snaplen) == -1) {
             TmqhOutputPacketpool(ptv->tv, p);
-            SCReturnInt(AFP_FAILURE);
+            SCReturnInt(AFP_SURI_FAILURE);
         }
     }
     /* Timestamp */
@@ -1038,7 +1049,7 @@ static inline int AFPParsePacketV3(AFPThreadVars *ptv, struct tpacket_block_desc
 
     if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
         TmqhOutputPacketpool(ptv->tv, p);
-        SCReturnInt(AFP_FAILURE);
+        SCReturnInt(AFP_SURI_FAILURE);
     }
 
     SCReturnInt(AFP_READ_OK);
@@ -1048,12 +1059,23 @@ static inline int AFPWalkBlock(AFPThreadVars *ptv, struct tpacket_block_desc *pb
 {
     int num_pkts = pbd->hdr.bh1.num_pkts, i;
     uint8_t *ppd;
+    int ret = 0;
 
     ppd = (uint8_t *)pbd + pbd->hdr.bh1.offset_to_first_pkt;
     for (i = 0; i < num_pkts; ++i) {
-        if (unlikely(AFPParsePacketV3(ptv, pbd,
-                             (struct tpacket3_hdr *)ppd) == AFP_FAILURE)) {
-            SCReturnInt(AFP_READ_FAILURE);
+        ret = AFPParsePacketV3(ptv, pbd,
+                               (struct tpacket3_hdr *)ppd);
+        switch (ret) {
+            case AFP_READ_OK:
+                break;
+            case AFP_SURI_FAILURE:
+                /* Internal error but let's just continue and
+                 * treat thenext packet */
+                break;
+            case AFP_READ_FAILURE:
+                SCReturnInt(AFP_READ_FAILURE);
+            default:
+                SCReturnInt(ret);
         }
         ppd = ppd + ((struct tpacket3_hdr *)ppd)->tp_next_offset;
     }
@@ -1075,6 +1097,7 @@ static int AFPReadFromRingV3(AFPThreadVars *ptv)
 {
 #ifdef HAVE_TPACKET_V3
     struct tpacket_block_desc *pbd;
+    int ret = 0;
 
     /* Loop till we have packets available */
     while (1) {
@@ -1090,9 +1113,10 @@ static int AFPReadFromRingV3(AFPThreadVars *ptv)
             SCReturnInt(AFP_READ_OK);
         }
 
-        if (unlikely(AFPWalkBlock(ptv, pbd) != AFP_READ_OK)) {
+        ret = AFPWalkBlock(ptv, pbd);
+        if (unlikely(ret != AFP_READ_OK)) {
             AFPFlushBlock(pbd);
-            SCReturnInt(AFP_READ_FAILURE);
+            SCReturnInt(ret);
         }
 
         AFPFlushBlock(pbd);
@@ -1496,9 +1520,8 @@ TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot)
                            ptv->iface, errno, strerror(errno));
                     AFPSwitchState(ptv, AFP_STATE_DOWN);
                     continue;
-                case AFP_FAILURE:
-                    AFPSwitchState(ptv, AFP_STATE_DOWN);
-                    SCReturnInt(TM_ECODE_FAILED);
+                case AFP_SURI_FAILURE:
+                    StatsIncr(ptv->tv, ptv->capture_errors);
                     break;
                 case AFP_KERNEL_DROP:
                     AFPDumpCounters(ptv);
@@ -2199,6 +2222,8 @@ TmEcode ReceiveAFPThreadInit(ThreadVars *tv, const void *initdata, void **data)
             ptv->tv);
     ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops",
             ptv->tv);
+    ptv->capture_errors = StatsRegisterCounter("capture.errors",
+            ptv->tv);
 #endif
 
     ptv->copy_mode = afpconfig->copy_mode;