Project

General

Profile

Actions

Bug #3435

closed

afl: Compile/make fails on openSUSE Leap-15.1

Added by Dave Peters almost 5 years ago. Updated over 4 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Target version:
Affected Versions:
Effort:
Difficulty:
Label:

Description

I am trying to compile suricata-5.0.1 on openSUSE Leap-15.1 but the build fails with error -

  CC       threads.o
  CC       tm-modules.o
  CC       tmqh-flow.o
  CC       tmqh-packetpool.o
  CC       tmqh-simple.o
  CC       tm-queuehandlers.o
  CC       tm-queues.o
  CC       tm-threads.o
tm-threads.c: In function ‘TmThreadsSlotPktAcqLoopAFL’:
tm-threads.c:509:9: error: implicit declaration of function ‘CheckSlot’ [-Werror=implicit-function-declaration]
         CheckSlot(slot);
         ^~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [Makefile:1813: tm-threads.o] Error 1
make[2]: Leaving directory '/usr/local/src/suricata/src'
make[1]: *** [Makefile:498: all-recursive] Error 1
make[1]: Leaving directory '/usr/local/src/suricata'
make: *** [Makefile:424: all] Error 2

My configure arguments are -

LIBS="-lrt -lnuma" CPPFLAGS="-I/usr/include/libnetfilter_queue/ -I/usr/include/libnfnetlink/" \
./configure --prefix=/usr/local --localstatedir=/var \
--disable-gccmarch-native --enable-gccprotect \
--enable-python --enable-afl --enable-unittests \
--enable-profiling --enable-coccinelle --enable-nflog \
--enable-nfqueue --enable-pfring --enable-prelude \
--enable-af-packet --enable-netmap --enable-libmagic \
--enable-non-bundled-htp \
--enable-luajit --enable-geoip --enable-hiredis \
--with-libpfring-libraries=/usr/local/lib64 \
--with-libpfring-includes=/usr/local/include \
--with-libpcap-libraries=/usr/local/lib64 \
--with-libpcap-includes=/usr/local/include/pcap \
--with-libhs-includes=/usr/include/hs \
--with-libhs-libraries=/usr/lib64 \
--with-libnss-libraries=/usr/lib64 \
--with-libnss-includes=/usr/include/nss3 \
--with-libnetfilter_queue-includes=/usr/include/libnetfilter_queue \
--with-libnetfilter_queue-libraries=/usr/lib64 \
--with-libnetfilter_log-includes=/usr/include/libnetfilter_log \
--with-libnetfilter_log-libraries=/usr/lib64 \
--with-netmap-includes=/usr/include/net 

Please let me know how to fix this.


Files

config.log (218 KB) config.log config.log Dave Peters, 01/04/2020 12:23 PM
Actions #1

Updated by Dave Peters almost 5 years ago

Additional information.

Actions #2

Updated by Dave Peters almost 5 years ago

Dave Peters wrote:

I am trying to compile suricata-5.0.1 on openSUSE Leap-15.1 but the build fails with error -

[...]

My configure arguments are -
[...]

Please let me know how to fix this.

I modified src/tm-thread.c and the compile/install went fine. I am not sure of the outcome though. Patch here -

--- src/tm-threads.c    2020-01-04 08:51:52.879568330 -0800
+++ src/tm-threads.c-orig       2020-01-04 08:52:08.863294255 -0800
@@ -70,24 +70,8 @@
 #define cpu_set_t cpuset_t
 #endif /* OS_FREEBSD */

-#ifdef OS_WIN32
-static inline void SleepUsec(uint64_t usec)
-{
-    uint64_t msec = 1;
-    if (usec > 1000) {
-        msec = usec / 1000;
-    }
-    Sleep(msec);
-}
-#define SleepMsec(msec) Sleep((msec))
-#else
-#define SleepUsec(usec) usleep((usec))
-#define SleepMsec(msec) usleep((msec) * 1000)
-#endif
-
 /* prototypes */
 static int SetCPUAffinity(uint16_t cpu);
-
 static void TmThreadDeinitMC(ThreadVars *tv);

 /* root of the threadvars list */
@@ -200,49 +184,72 @@
  */
 static int TmThreadTimeoutLoop(ThreadVars *tv, TmSlot *s)
 {
-    TmSlot *stream_slot = NULL, *slot = NULL;
-    int run = 1;
+    TmSlot *fw_slot = NULL;
     int r = TM_ECODE_OK;

-    for (slot = s; slot != NULL; slot = slot->slot_next) {
-        if (slot->tm_id == TMM_FLOWWORKER)
-        {
-            stream_slot = slot;
+    for (TmSlot *slot = s; slot != NULL; slot = slot->slot_next) {
+        if (slot->tm_id == TMM_FLOWWORKER) {
+            fw_slot = slot;
             break;
         }
     }

-    if (tv->stream_pq == NULL || stream_slot == NULL) {
-        SCLogDebug("not running TmThreadTimeoutLoop %p/%p", tv->stream_pq, stream_slot);
+    if (tv->stream_pq == NULL || fw_slot == NULL) {
+        SCLogDebug("not running TmThreadTimeoutLoop %p/%p", tv->stream_pq, fw_slot);
         return r;
     }

     SCLogDebug("flow end loop starting");
-    while(run) {
-        Packet *p;
-        if (tv->stream_pq->len != 0) {
-            SCMutexLock(&tv->stream_pq->mutex_q);
-            p = PacketDequeue(tv->stream_pq);
-            SCMutexUnlock(&tv->stream_pq->mutex_q);
-            BUG_ON(p == NULL);
-
-            if ((r = TmThreadsSlotProcessPkt(tv, stream_slot, p) != TM_ECODE_OK)) {
-                if (r == TM_ECODE_FAILED)
-                    run = 0;
+    while (1) {
+        SCMutexLock(&tv->stream_pq->mutex_q);
+        uint32_t len = tv->stream_pq->len;
+        SCMutexUnlock(&tv->stream_pq->mutex_q);
+        if (len > 0) {
+            while (len--) {
+                SCMutexLock(&tv->stream_pq->mutex_q);
+                Packet *p = PacketDequeue(tv->stream_pq);
+                SCMutexUnlock(&tv->stream_pq->mutex_q);
+                if (likely(p)) {
+                    if ((r = TmThreadsSlotProcessPkt(tv, fw_slot, p) != TM_ECODE_OK)) {
+                        if (r == TM_ECODE_FAILED)
+                            break;
+                    }
+                }
             }
         } else {
+            if (TmThreadsCheckFlag(tv, THV_KILL)) {
+                break;
+            }
             SleepUsec(1);
         }
-
-        if (tv->stream_pq->len == 0 && TmThreadsCheckFlag(tv, THV_KILL)) {
-            run = 0;
-        }
     }
     SCLogDebug("flow end loop complete");
+    StatsSyncCounters(tv);

     return r;
 }

+/** \internal
+ *  \brief check 'slot' pre_pq and post_pq at thread cleanup
+ *         and dump detailed info about the state of the packets
+ *         and threads if in a unexpected state.
+ */
+static void CheckSlot(const TmSlot *slot)
+{
+    if (slot->slot_pre_pq.len || slot->slot_post_pq.len) {
+        for (Packet *xp = slot->slot_pre_pq.top; xp != NULL; xp = xp->next) {
+            SCLogNotice("pre_pq: slot id %u slot tm_id %u pre_pq.len %u packet src %s",
+                    slot->id, slot->tm_id, slot->slot_pre_pq.len, PktSrcToString(xp->pkt_src));
+        }
+        for (Packet *xp = slot->slot_post_pq.top; xp != NULL; xp = xp->next) {
+            SCLogNotice("post_pq: slot id %u slot tm_id %u post_pq.len %u packet src %s",
+                    slot->id, slot->tm_id, slot->slot_post_pq.len, PktSrcToString(xp->pkt_src));
+        }
+        TmThreadDumpThreads();
+        abort();
+    }
+}
+
 /*

     pcap/nfq
@@ -382,9 +389,7 @@
                 goto error;
             }
         }
-
-        BUG_ON(slot->slot_pre_pq.len);
-        BUG_ON(slot->slot_post_pq.len);
+        CheckSlot(slot);
     }

     tv->stream_pq = NULL;
@@ -501,8 +506,7 @@
             }
         }

-        BUG_ON(slot->slot_pre_pq.len);
-        BUG_ON(slot->slot_post_pq.len);
+        CheckSlot(slot);
     }

     tv->stream_pq = NULL;
@@ -662,8 +666,7 @@
                 goto error;
             }
         }
-        BUG_ON(s->slot_pre_pq.len);
-        BUG_ON(s->slot_post_pq.len);
+        CheckSlot(s);
     }

     SCLogDebug("%s ending", tv->name);
@@ -798,14 +801,9 @@

 ThreadVars *TmThreadsGetTVContainingSlot(TmSlot *tm_slot)
 {
-    ThreadVars *tv;
-    int i;
-
     SCMutexLock(&tv_root_lock);
-
-    for (i = 0; i < TVT_MAX; i++) {
-        tv = tv_root[i];
-
+    for (int i = 0; i < TVT_MAX; i++) {
+        ThreadVars *tv = tv_root[i];
         while (tv) {
             TmSlot *slots = tv->tm_slots;
             while (slots != NULL) {
@@ -818,9 +816,7 @@
             tv = tv->next;
         }
     }
-
     SCMutexUnlock(&tv_root_lock);
-
     return NULL;
 }

@@ -884,16 +880,11 @@
  */
 TmSlot *TmSlotGetSlotForTM(int tm_id)
 {
-    ThreadVars *tv = NULL;
-    TmSlot *slots;
-    int i;
-
     SCMutexLock(&tv_root_lock);
-
-    for (i = 0; i < TVT_MAX; i++) {
-        tv = tv_root[i];
+    for (int i = 0; i < TVT_MAX; i++) {
+        ThreadVars *tv = tv_root[i];
         while (tv) {
-            slots = tv->tm_slots;
+            TmSlot *slots = tv->tm_slots;
             while (slots != NULL) {
                 if (slots->tm_id == tm_id) {
                     SCMutexUnlock(&tv_root_lock);
@@ -904,9 +895,7 @@
             tv = tv->next;
         }
     }
-
     SCMutexUnlock(&tv_root_lock);
-
     return NULL;
 }

@@ -1434,6 +1423,36 @@
     return;
 }

+static bool ThreadStillHasPackets(ThreadVars *tv)
+{
+    if (tv->inq != NULL) {
+        /* we wait till we dry out all the inq packets, before we
+         * kill this thread.  Do note that you should have disabled
+         * packet acquire by now using TmThreadDisableReceiveThreads()*/
+        if (!(strlen(tv->inq->name) == strlen("packetpool") &&
+              strcasecmp(tv->inq->name, "packetpool") == 0)) {
+            PacketQueue *q = &trans_q[tv->inq->id];
+            SCMutexLock(&q->mutex_q);
+            uint32_t len = q->len;
+            SCMutexUnlock(&q->mutex_q);
+            if (len != 0) {
+                return true;
+            }
+        }
+    }
+
+    if (tv->stream_pq != NULL) {
+        SCMutexLock(&tv->stream_pq->mutex_q);
+        uint32_t len = tv->stream_pq->len;
+        SCMutexUnlock(&tv->stream_pq->mutex_q);
+
+        if (len != 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
 /**
  * \brief Kill a thread.
  *
@@ -1454,19 +1473,6 @@
         return 1;
     }

-    if (tv->inq != NULL) {
-        /* we wait till we dry out all the inq packets, before we
-         * kill this thread.  Do note that you should have disabled
-         * packet acquire by now using TmThreadDisableReceiveThreads()*/
-        if (!(strlen(tv->inq->name) == strlen("packetpool") &&
-              strcasecmp(tv->inq->name, "packetpool") == 0)) {
-            PacketQueue *q = &trans_q[tv->inq->id];
-            if (q->len != 0) {
-                return 0;
-            }
-        }
-    }
-
     /* set the thread flag informing the thread that it needs to be
      * terminated */
     TmThreadsSetFlag(tv, THV_KILL);
@@ -1511,7 +1517,7 @@
 /** \internal
  *
  *  \brief make sure that all packet threads are done processing their
- *         in-flight packets
+ *         in-flight packets, including 'injected' flow packets.
  */
 static void TmThreadDrainPacketThreads(void)
 {
@@ -1533,23 +1539,16 @@
     /* all receive threads are part of packet processing threads */
     tv = tv_root[TVT_PPT];
     while (tv) {
-        if (tv->inq != NULL) {
+        if (ThreadStillHasPackets(tv)) {
             /* we wait till we dry out all the inq packets, before we
              * kill this thread.  Do note that you should have disabled
              * packet acquire by now using TmThreadDisableReceiveThreads()*/
-            if (!(strlen(tv->inq->name) == strlen("packetpool") &&
-                        strcasecmp(tv->inq->name, "packetpool") == 0)) {
-                PacketQueue *q = &trans_q[tv->inq->id];
-                if (q->len != 0) {
-                    SCMutexUnlock(&tv_root_lock);
+            SCMutexUnlock(&tv_root_lock);

-                    /* sleep outside lock */
-                    SleepMsec(1);
-                    goto again;
-                }
-            }
+            /* sleep outside lock */
+            SleepMsec(1);
+            goto again;
         }
-
         tv = tv->next;
     }

@@ -1605,20 +1604,14 @@
         }

         if (disable) {
-            if (tv->inq != NULL) {
+            if (ThreadStillHasPackets(tv)) {
                 /* we wait till we dry out all the inq packets, before we
                  * kill this thread.  Do note that you should have disabled
                  * packet acquire by now using TmThreadDisableReceiveThreads()*/
-                if (!(strlen(tv->inq->name) == strlen("packetpool") &&
-                      strcasecmp(tv->inq->name, "packetpool") == 0)) {
-                    PacketQueue *q = &trans_q[tv->inq->id];
-                    if (q->len != 0) {
-                        SCMutexUnlock(&tv_root_lock);
-                        /* don't sleep while holding a lock */
-                        SleepMsec(1);
-                        goto again;
-                    }
-                }
+                SCMutexUnlock(&tv_root_lock);
+                /* don't sleep while holding a lock */
+                SleepMsec(1);
+                goto again;
             }

             /* we found a receive TV. Send it a KILL_PKTACQ signal. */
@@ -1657,6 +1650,21 @@
     return;
 }

+static void TmThreadDebugValidateNoMorePackets(void)
+{
+#ifdef DEBUG_VALIDATION
+    SCMutexLock(&tv_root_lock);
+    for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
+        if (ThreadStillHasPackets(tv)) {
+            SCMutexUnlock(&tv_root_lock);
+            TmThreadDumpThreads();
+            abort();
+        }
+    }
+    SCMutexUnlock(&tv_root_lock);
+#endif
+}
+
 /**
  * \brief Disable all threads having the specified TMs.
  */
@@ -1668,6 +1676,7 @@

     /* first drain all packet threads of their packets */
     TmThreadDrainPacketThreads();
+    TmThreadDebugValidateNoMorePackets();

     gettimeofday(&start_ts, NULL);
 again:
@@ -1688,22 +1697,6 @@
      * receive TM amongst the slots in a tv, it indicates we are done
      * with all receive threads */
     while (tv) {
-        if (tv->inq != NULL) {
-            /* we wait till we dry out all the inq packets, before we
-             * kill this thread.  Do note that you should have disabled
-             * packet acquire by now using TmThreadDisableReceiveThreads()*/
-            if (!(strlen(tv->inq->name) == strlen("packetpool") &&
-                        strcasecmp(tv->inq->name, "packetpool") == 0)) {
-                PacketQueue *q = &trans_q[tv->inq->id];
-                if (q->len != 0) {
-                    SCMutexUnlock(&tv_root_lock);
-                    /* don't sleep while holding a lock */
-                    SleepMsec(1);
-                    goto again;
-                }
-            }
-        }
-
         /* we found our receive TV.  Send it a KILL signal.  This is all
          * we need to do to kill receive threads */
         TmThreadsSetFlag(tv, THV_KILL);
@@ -2227,6 +2220,46 @@
     return cnt;
 }

+static void TmThreadDoDumpSlots(const ThreadVars *tv)
+{
+    for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
+        TmModule *m = TmModuleGetById(s->tm_id);
+        SCLogNotice("tv %p: -> slot %p id %d tm_id %d name %s %s",
+            tv, s, s->id, s->tm_id, m->name, (tv->type == 0 && tv->stream_pq == &s->slot_post_pq) ? "<==== stream_pq" : "");
+        if (tv->type == 0 && tv->stream_pq == &s->slot_pre_pq) {
+            SCLogNotice("tv %p: -> slot %p/%d holds stream_pq %p IN PRE_PQ SUPER WEIRD", tv, s, s->id, tv->stream_pq);
+        }
+        for (Packet *xp = s->slot_pre_pq.top; xp != NULL; xp = xp->next) {
+            SCLogNotice("tv %p: ==> pre_pq: slot id %u slot tm_id %u pre_pq.len %u packet src %s",
+                    tv, s->id, s->tm_id, s->slot_pre_pq.len, PktSrcToString(xp->pkt_src));
+        }
+        for (Packet *xp = s->slot_post_pq.top; xp != NULL; xp = xp->next) {
+            SCLogNotice("tv %p: ==> post_pq: slot id %u slot tm_id %u post_pq.len %u packet src %s",
+                    tv, s->id, s->tm_id, s->slot_post_pq.len, PktSrcToString(xp->pkt_src));
+        }
+    }
+}
+
+void TmThreadDumpThreads(void)
+{
+    SCMutexLock(&tv_root_lock);
+    for (int i = 0; i < TVT_MAX; i++) {
+        ThreadVars *tv = tv_root[i];
+        while (tv != NULL) {
+            const uint32_t flags = SC_ATOMIC_GET(tv->flags);
+            SCLogNotice("tv %p: type %u name %s tmm_flags %02X flags %X stream_pq %p",
+                    tv, tv->type, tv->name, tv->tmm_flags, flags, tv->stream_pq);
+            if (tv->inq && tv->stream_pq == &trans_q[tv->inq->id]) {
+                SCLogNotice("tv %p: stream_pq at tv->inq %u", tv, tv->inq->id);
+            }
+            TmThreadDoDumpSlots(tv);
+            tv = tv->next;
+        }
+    }
+    SCMutexUnlock(&tv_root_lock);
+    TmThreadsListThreads();
+}
+
 typedef struct Thread_ {
     ThreadVars *tv;     /**< threadvars structure */
     const char *name;
@@ -2256,7 +2289,15 @@
         t = &thread_store.threads[s];
         if (t == NULL || t->in_use == 0)
             continue;
-        SCLogInfo("Thread %"PRIuMAX", %s type %d, tv %p", (uintmax_t)s+1, t->name, t->type, t->tv);
+
+        SCLogNotice("Thread %"PRIuMAX", %s type %d, tv %p in_use %d",
+                (uintmax_t)s+1, t->name, t->type, t->tv, t->in_use);
+        if (t->tv) {
+            ThreadVars *tv = t->tv;
+            const uint32_t flags = SC_ATOMIC_GET(tv->flags);
+            SCLogNotice("tv %p type %u name %s tmm_flags %02X flags %X",
+                    tv, tv->type, tv->name, tv->tmm_flags, flags);
+        }
     }

     SCMutexUnlock(&thread_store_lock);

Please let me know whether this is legit or my binary will break/die.

Actions #3

Updated by Dave Peters almost 5 years ago

The error is gone after removing --enable-afl. Thanks to Jason Ish for suggesting this on irc.

# suricata --build-info
This is Suricata version 5.0.1 RELEASE
Features: UNITTESTS NFQ PCAP_SET_BUFF PF_RING AF_PACKET NETMAP HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK PCRE_JIT HAVE_NSS HAVE_LUA HAVE_LUAJIT HAVE_LIBJANSSON PROFILING TLS MAGIC RUST 
SIMD support: none
Atomic intrinsics: 1 2 4 8 byte(s)
64-bits, Little-endian architecture
GCC version 7.4.0, C version 199901
compiled with -fstack-protector
compiled with _FORTIFY_SOURCE=2
L1 cache line size (CLS)=64
thread local storage method: __thread
compiled with LibHTP v0.5.32, linked against LibHTP v0.5.32

Suricata Configuration:
  AF_PACKET support:                       yes
  eBPF support:                            no
  XDP support:                             no
  PF_RING support:                         yes
  NFQueue support:                         yes
  NFLOG support:                           yes
  IPFW support:                            no
  Netmap support:                          yes v13
  DAG enabled:                             no
  Napatech enabled:                        no
  WinDivert enabled:                       no

  Unix socket enabled:                     yes
  Detection enabled:                       yes

  Libmagic support:                        yes
  libnss support:                          yes
  libnspr support:                         yes
  libjansson support:                      yes
  hiredis support:                         yes
  hiredis async with libevent:             yes
  Prelude support:                         yes
  PCRE jit:                                yes
  LUA support:                             yes, through luajit
  libluajit:                               yes
  GeoIP2 support:                          yes
  Non-bundled htp:                         yes
  Old barnyard2 support:                   no
  Hyperscan support:                       yes
  Libnet support:                          yes
  liblz4 support:                          yes

  Rust support:                            yes
  Rust strict mode:                        no
  Rust compiler path:                      /usr/bin/rustc
  Rust compiler version:                   rustc 1.36.0
  Cargo path:                              /usr/bin/cargo
  Cargo version:                           cargo 1.36.0
  Cargo vendor:                            no

  Python support:                          yes
  Python path:                             /usr/bin/python3
  Python distutils                         yes
  Python yaml                              yes
  Install suricatactl:                     yes
  Install suricatasc:                      yes
  Install suricata-update:                 yes

  Profiling enabled:                       yes
  Profiling locks enabled:                 no

Development settings:
  Coccinelle / spatch:                     yes
  Unit tests enabled:                      yes
  Debug output enabled:                    no
  Debug validation enabled:                no

Generic build parameters:
  Installation prefix:                     /usr
  Configuration directory:                 /etc/suricata/
  Log directory:                           /var/log/suricata/

  --prefix                                 /usr
  --sysconfdir                             /etc
  --localstatedir                          /var
  --datarootdir                            /usr/share

  Host:                                    x86_64-pc-linux-gnu
  Compiler:                                gcc (exec name) / gcc (real)
  GCC Protect enabled:                     yes
  GCC march native enabled:                no
  GCC Profile enabled:                     no
  Position Independent Executable enabled: yes
  CFLAGS                                   -g -O2 -I${srcdir}/../rust/gen/c-headers
  PCAP_CFLAGS                               -I/usr/local/include
  SECCFLAGS                                -fstack-protector -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security

Actions #4

Updated by Victor Julien almost 5 years ago

  • Subject changed from Compile/make fails on openSUSE Leap-15.1 to afl: Compile/make fails on openSUSE Leap-15.1
  • Effort deleted (medium)
  • Difficulty deleted (medium)
  • Label deleted (Beginner)

It seems the issue here is that --enable-afl was used. This is meant only for fuzz testing certain Suricata internals.

Actions #5

Updated by Zackeus Bengtsson almost 5 years ago

Victor Julien wrote:

It seems the issue here is that --enable-afl was used. This is meant only for fuzz testing certain Suricata internals.

I had the same issue. By using git bisect between a known good version (suricata-4.1.5) and known bad (suricata-4.1.6) I found that commit "166b2a8216f0c7d8e4b52f990f319fe3aee9f6ef - threading: improve thread queues checking by dumping more info" introduced the issue, and has been present since.

The issue is that CheckSlot is declared within the scope of "#ifndef AFLFUZZ_PCAP_RUNMODE" (line 250 tm-threads.c), but is also used outside the scope, within #ifdef AFLFUZZ_PCAP_RUNMODE (line 582 & 682).

Hope this helps and that you'll get a fix out :)

Actions #6

Updated by Victor Julien over 4 years ago

  • Status changed from New to Closed
  • Assignee set to Victor Julien
  • Target version set to 6.0.0beta1
Actions

Also available in: Atom PDF