diff options
Diffstat (limited to 'framework/src/suricata/qa/coccinelle')
13 files changed, 495 insertions, 0 deletions
diff --git a/framework/src/suricata/qa/coccinelle/Makefile.am b/framework/src/suricata/qa/coccinelle/Makefile.am new file mode 100644 index 00000000..8ceebe06 --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/Makefile.am @@ -0,0 +1,21 @@ +EXTRA_DIST= access-pkt-packet.cocci \ + action-pkt.cocci \ + banned-functions.cocci \ + direct-packet.cocci \ + malloc-error-check.cocci \ + pktnotset-packet.cocci \ + size_t.cocci \ + struct-flags.cocci \ + sz3.cocci \ + run_check.sh struct-flags.py + +if HAVE_COCCINELLE +struct-flags.cocci: + $(srcdir)/struct-flags.py > $(top_builddir)/qa/coccinelle/struct-flags.cocci + +check: + $(top_srcdir)/qa/coccinelle/run_check.sh + +distclean-local: + -rm $(top_builddir)/qa/coccinelle/struct-flags.cocci +endif diff --git a/framework/src/suricata/qa/coccinelle/access-pkt-packet.cocci b/framework/src/suricata/qa/coccinelle/access-pkt-packet.cocci new file mode 100644 index 00000000..681848ec --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/access-pkt-packet.cocci @@ -0,0 +1,55 @@ +@init@ +typedef Packet; +Packet *p; +expression E; +statement S; +@@ + +( +memset(p, ...); +p->pkt = E; +| +p = SCCalloc(...); +S +p->pkt = E; +) + +@pktfield depends on !init@ +identifier func !~ "^PacketCopyDataOffset$"; +Packet *p; +position p1; +@@ + +func(...) { +<... +p->pkt@p1 +...> +} + +@ script:python @ +p1 << pktfield.p1; +@@ + +print "Invalid Packet->pkt usage, GET_PKT_DATA macro must be used at %s:%s" % (p1[0].file, p1[0].line) +import sys +sys.exit(1) + +@pktlenfield@ +identifier func !~ "^PacketCopyDataOffset$"; +Packet *p; +position p1; +@@ + +func(...) { +<... +p->pktlen@p1 +...> +} + +@ script:python @ +p1 << pktlenfield.p1; +@@ + +print "Invalid Packet->pktlen usage, GET_PKT_LEN macro must be used at %s:%s" % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/action-pkt.cocci b/framework/src/suricata/qa/coccinelle/action-pkt.cocci new file mode 100644 index 00000000..1a66721a --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/action-pkt.cocci @@ -0,0 +1,15 @@ +@action@ +typedef Packet; +Packet *p; +position p1; +@@ + +p->action@p1 + +@ script:python @ +p1 << action.p1; +@@ + +print "Invalid usage of p->action, please use macro at %s:%s" % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/banned-functions.cocci b/framework/src/suricata/qa/coccinelle/banned-functions.cocci new file mode 100644 index 00000000..5913521c --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/banned-functions.cocci @@ -0,0 +1,15 @@ +@banned@ +identifier i; +position p1; +@@ + +\(strtok@i\|sprintf@i\|strcat@i\|strcpy@i\|strncpy@i\|strncat@i\|strndup@i\|strchrdup@i\)(...)@p1 + +@script:python@ +p1 << banned.p1; +i << banned.i; +@@ + +print("Banned function '%s' used at %s:%s" % (i, p1[0].file, p1[0].line)) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/direct-packet.cocci b/framework/src/suricata/qa/coccinelle/direct-packet.cocci new file mode 100644 index 00000000..dbe1f98b --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/direct-packet.cocci @@ -0,0 +1,15 @@ +@directpacket@ +identifier p; +typedef Packet; +position p1; +@@ + +Packet p@p1; + +@ script:python @ +p1 << directpacket.p1; +@@ + +print "Invalid Packet definition, explicit allocation must be used at %s:%s" % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/malloc-error-check.cocci b/framework/src/suricata/qa/coccinelle/malloc-error-check.cocci new file mode 100644 index 00000000..b245189a --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/malloc-error-check.cocci @@ -0,0 +1,63 @@ +@malloced@ +expression x; +position p1; +identifier func =~ "(SCMalloc|SCStrdup|SCCalloc|SCMallocAligned|SCRealloc)"; +@@ + +x@p1 = func(...) + +@inlinetested@ +expression x, E; +statement S; +position malloced.p1; +identifier func =~ "(SCMalloc|SCStrdup|SCCalloc|SCMallocAligned|SCRealloc)"; +@@ + +( +if ((x@p1 = func(...)) == NULL) S +| +if (E && (x@p1 = func(...)) == NULL) S +) + +@realloc exists@ +position malloced.p1; +expression x, E1; +identifier func =~ "(SCMalloc|SCCalloc|SCMallocAligned)"; +@@ + +x@p1 = func(...) +... when != x +x = SCRealloc(x, E1) + +@istested depends on !realloc exists@ +expression x, E1; +position malloced.p1; +statement S1, S2; +identifier func =~ "(SCMalloc|SCStrdup|SCCalloc|SCMallocAligned|SCRealloc)"; +@@ + +x@p1 = func(...) +... when != x +( +if (unlikely(x == NULL)) S1 +| +if (unlikely(x == NULL)) S1 else S2 +| +if (likely(x != NULL)) S1 +| +if (x == NULL) S1 +| +if (x != NULL) S1 else S2 +| +if (x && E1) S1 +| +BUG_ON(x == NULL) +) + + +@script:python depends on !realloc && !istested && !inlinetested@ +p1 << malloced.p1; +@@ +print "Structure malloced at %s:%s but error is not checked." % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/pktnotset-packet.cocci b/framework/src/suricata/qa/coccinelle/pktnotset-packet.cocci new file mode 100644 index 00000000..ab6a98c1 --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/pktnotset-packet.cocci @@ -0,0 +1,29 @@ +@zeroed@ +typedef Packet; +typedef uint8_t; +Packet *p; +position p1; +@@ + +memset(p@p1, 0, ...); + +@isset@ +Packet *p; +position zeroed.p1; +@@ + +memset(p@p1, 0, ...); +... when != p +( +p->pkt +| +PACKET_INITIALIZE(p) +) + +@script:python depends on !isset@ +p1 << zeroed.p1; +@@ + +print "Packet zeroed at %s:%s but pkt field is not set afterward." % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/realloc.cocci b/framework/src/suricata/qa/coccinelle/realloc.cocci new file mode 100644 index 00000000..0b828807 --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/realloc.cocci @@ -0,0 +1,18 @@ +@realloc@ +expression x, E; +type ty; +position p1; +@@ + +( +x@p1 = SCRealloc(x, E) +| +x@p1 = (ty *) SCRealloc(x, E) +) + +@script:python@ +p1 << realloc.p1; +@@ +print "Structure reallocated at %s:%s but original pointer is lost and not freed in case of error." % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/run_check.sh b/framework/src/suricata/qa/coccinelle/run_check.sh new file mode 100755 index 00000000..79ec9cc6 --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/run_check.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +if [ $1 ]; then + case $1 in + *[ch]) + LIST=$@; + ;; + *..*) + LIST=$(git diff --pretty="format:" --name-only $1 | grep -E '[ch]$') + PREFIX=$(git rev-parse --show-toplevel)/ + ;; + *) + LIST=$(git show --pretty="format:" --name-only $1 | grep -E '[ch]$') + PREFIX=$(git rev-parse --show-toplevel)/ + ;; + esac +else + LIST=$(git ls-tree -r --name-only --full-tree HEAD src/ | grep -E '*.c$') + PREFIX=$(git rev-parse --show-toplevel)/ +fi + +if [ -z "$CONCURRENCY_LEVEL" ]; then + CONCURRENCY_LEVEL=1 + echo "No concurrency" +else + echo "Using concurrency level $CONCURRENCY_LEVEL" +fi + +for SMPL in $(git rev-parse --show-toplevel)/qa/coccinelle/*.cocci; do + echo "Testing cocci file: $SMPL" + if command -v parallel >/dev/null; then + echo -n $LIST | parallel -d ' ' -j $CONCURRENCY_LEVEL spatch --very-quiet -sp_file $SMPL --undefined UNITTESTS $PREFIX{} || if [ -z "$NOT_TERMINAL" ]; then exit 1; fi + else + for FILE in $LIST ; do + spatch --very-quiet -sp_file $SMPL --undefined UNITTESTS $PREFIX$FILE || if [ -z "$NOT_TERMINAL" ]; then exit 1; fi + done + fi +done + +exit 0 diff --git a/framework/src/suricata/qa/coccinelle/size_t.cocci b/framework/src/suricata/qa/coccinelle/size_t.cocci new file mode 100644 index 00000000..4bd5b9f2 --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/size_t.cocci @@ -0,0 +1,44 @@ +@sizet@ +size_t p; +identifier func =~ "^(sprintf|printf|SCLog.*)$"; +identifier funcn =~ "^.*nprintf$"; +position p1; +typedef uint16_t; +typedef uint32_t; +typedef uint64_t; +expression E1, E2; +@@ + +( +func(..., p, ...)@p1; +| +func(..., (int) p, ...)@p1; +| +func(..., (unsigned int) p, ...)@p1; +| +func(..., (uint16_t) p, ...)@p1; +| +func(..., (uint32_t) p, ...)@p1; +| +func(..., (uint64_t) p, ...)@p1; +| +funcn(E1, E2,..., p, ...)@p1; +| +funcn(E1, E2,..., (int) p, ...)@p1; +| +funcn(E1, E2,..., (unsigned int) p, ...)@p1; +| +funcn(E1, E2,..., (uint16_t) p, ...)@p1; +| +funcn(E1, E2,..., (uint32_t) p, ...)@p1; +| +funcn(E1, E2,..., (uint64_t) p, ...)@p1; +) + +@ script:python @ +p1 << sizet.p1; +@@ + +print "Invalid printf with size_t (not casted to uintmax_t) at %s:%s" % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/struct-flags.cocci b/framework/src/suricata/qa/coccinelle/struct-flags.cocci new file mode 100644 index 00000000..45fab734 --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/struct-flags.cocci @@ -0,0 +1,77 @@ +@flags@ +SignatureHeader *struct0; +identifier struct_flags0 =~ "^(?!SIG_FLAG).+"; +Signature *struct1; +identifier struct_flags1 =~ "^(?!SIG_FLAG).+"; +Signature *struct2; +identifier struct_flags2 =~ "^(?!SIG_FLAG_INIT_).+"; +Flow *struct3; +identifier struct_flags3 =~ "^(?!FLOW_).+"; +TcpSegment *struct4; +identifier struct_flags4 =~ "^(?!SEGMENTTCP_FLAG).+"; +TcpStream *struct5; +identifier struct_flags5 =~ "^(?!STREAMTCP_STREAM_FLAG_).+"; +TcpSession *struct6; +identifier struct_flags6 =~ "^(?!STREAMTCP_FLAG).+"; +Packet *struct7; +identifier struct_flags7 =~ "^(?!FLOW_PKT_).+"; +position p1; +@@ + +( +struct0->flags@p1 |= struct_flags0 +| +struct0->flags@p1 & struct_flags0 +| +struct0->flags@p1 &= ~struct_flags0 +| +struct1->flags@p1 |= struct_flags1 +| +struct1->flags@p1 & struct_flags1 +| +struct1->flags@p1 &= ~struct_flags1 +| +struct2->init_flags@p1 |= struct_flags2 +| +struct2->init_flags@p1 & struct_flags2 +| +struct2->init_flags@p1 &= ~struct_flags2 +| +struct3->flags@p1 |= struct_flags3 +| +struct3->flags@p1 & struct_flags3 +| +struct3->flags@p1 &= ~struct_flags3 +| +struct4->flags@p1 |= struct_flags4 +| +struct4->flags@p1 & struct_flags4 +| +struct4->flags@p1 &= ~struct_flags4 +| +struct5->flags@p1 |= struct_flags5 +| +struct5->flags@p1 & struct_flags5 +| +struct5->flags@p1 &= ~struct_flags5 +| +struct6->flags@p1 |= struct_flags6 +| +struct6->flags@p1 & struct_flags6 +| +struct6->flags@p1 &= ~struct_flags6 +| +struct7->flowflags@p1 |= struct_flags7 +| +struct7->flowflags@p1 & struct_flags7 +| +struct7->flowflags@p1 &= ~struct_flags7 +) + +@script:python@ +p1 << flags.p1; +@@ + +print "Invalid usage of flags field at %s:%s, flags value is incorrect (wrong family)." % (p1[0].file, p1[0].line) +import sys +sys.exit(1) diff --git a/framework/src/suricata/qa/coccinelle/struct-flags.py b/framework/src/suricata/qa/coccinelle/struct-flags.py new file mode 100755 index 00000000..3a91157b --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/struct-flags.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +import re +from os import listdir + +SRC_DIR="../../src/" + +class Structure: + def __init__(self, string): + (self.struct, self.flags, self.values) = string.split(":") + +cmd = "grep -h coccinelle ../../src/*[ch] | sed -e 's/.*coccinelle: \(.*\) \*\//\1/'" + +struct_list = [] + +dirList = listdir(SRC_DIR) +for fname in dirList: + if re.search("\.[ch]$", fname): + for line in open(SRC_DIR + fname): + if "coccinelle:" in line: + m = re.search("coccinelle: (.*) \*\/", line) + struct = Structure(m.group(1)) + struct_list.append(struct) + +header = "@flags@" +body = [] + +i = 0 +for struct in struct_list: + header += """ +%s *struct%d; +identifier struct_flags%d =~ "^(?!%s).+";""" % ( struct.struct, i, i, struct.values) + + body.append(""" +struct%d->%s@p1 |= struct_flags%d +| +struct%d->%s@p1 & struct_flags%d +| +struct%d->%s@p1 &= ~struct_flags%d +""" % (i, struct.flags, i, i, struct.flags, i, i, struct.flags, i)) + + i+=1 + +print header +print "position p1;" +print "@@" +print "" +print "(" + "|".join(body) + ")" +print "" +print """@script:python@ +p1 << flags.p1; +@@ + +print "Invalid usage of flags field at %s:%s, flags value is incorrect (wrong family)." % (p1[0].file, p1[0].line) +import sys +sys.exit(1)""" diff --git a/framework/src/suricata/qa/coccinelle/sz3.cocci b/framework/src/suricata/qa/coccinelle/sz3.cocci new file mode 100644 index 00000000..37a8877b --- /dev/null +++ b/framework/src/suricata/qa/coccinelle/sz3.cocci @@ -0,0 +1,48 @@ +// +// Take size of pointed value, not pointer +// +// Target: Linux, Generic +// Copyright: 2012 - LIP6/INRIA +// License: Licensed under GPLv2 or any later version. +// Author: Julia Lawall <Julia.Lawall@lip6.fr> +// URL: http://coccinelle.lip6.fr/ +// URL: http://coccinellery.org/ +// Modified by Eric Leblond <eric@regit.org> for suricata test system + +@preuse@ +expression *e; +type T; +identifier f; +position p1; +@@ + +f(..., +sizeof(e@p1) +,...,(T)e,...) + +@ script:python @ +p1 << preuse.p1; +@@ + +print "Size of pointed value not pointer used at %s:%s" % (p1[0].file, p1[0].line) +import sys +sys.exit(1) + +@postuse@ +expression *e; +type T; +identifier f; +position p1; +@@ + +f(...,(T)e,..., +sizeof(e@p1) +,...) + +@ script:python @ +p1 << postuse.p1; +@@ + +print "Size of pointed value not pointer used at %s:%s" % (p1[0].file, p1[0].line) +import sys +sys.exit(1) |