summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Štetiar <ynezz@true.cz>2020-10-03 01:53:53 +0200
committerPetr Štetiar <ynezz@true.cz>2020-10-03 09:20:48 +0200
commit9bd361ca323637b047ecfdf5de3c8cfbf64698d6 (patch)
tree666c966af10fd2eae243fcd9361768caf6da38a9
parentec8d3233948603485e1b97384113fac9f1bab5d6 (diff)
downloaduci-9bd361ca323637b047ecfdf5de3c8cfbf64698d6.tar.gz
tests: add libFuzzer based fuzzing
LibFuzzer is in-process, coverage-guided, evolutionary fuzzing engine. LibFuzzer is linked with the library under test, and feeds fuzzed inputs to the library via a specific fuzzing entrypoint (aka "target function"); the fuzzer then tracks which areas of the code are reached, and generates mutations on the corpus of input data in order to maximize the code coverage. So lets use libFuzzer to fuzz uci_import for the start. Ref: https://llvm.org/docs/LibFuzzer.html Signed-off-by: Petr Štetiar <ynezz@true.cz>
-rw-r--r--tests/CMakeLists.txt4
-rw-r--r--tests/fuzz/CMakeLists.txt18
-rw-r--r--tests/fuzz/corpus/231ee80a172b8e1749b9d91867989d88e4faf7bbbin0 -> 15 bytes
-rw-r--r--tests/fuzz/corpus/26a6253fc1eb695b61a2fc7640ee4c03c19e438ebin0 -> 9 bytes
-rw-r--r--tests/fuzz/corpus/29a6e206439d792afba5e8e9c1fdf55e65a1145dbin0 -> 4 bytes
-rw-r--r--tests/fuzz/corpus/51045ac5401085f5727c6d3c1cac5f8cc32a29271
-rw-r--r--tests/fuzz/corpus/845dcf3f15f3c28235e6be148a690e7f03b07f65bin0 -> 22 bytes
-rw-r--r--tests/fuzz/corpus/bb589d0621e5472f470fa3425a234c74b1e202e81
-rw-r--r--tests/fuzz/corpus/ea387894a296772f96706df8b999a52d9334c746bin0 -> 5 bytes
-rw-r--r--tests/fuzz/corpus/id:000000,sig:11,src:000001,op:flip1,pos:24bin0 -> 44 bytes
-rw-r--r--tests/fuzz/corpus/id:000008,sig:11,src:000022,op:arith8,pos:42,val:+26bin0 -> 43 bytes
-rw-r--r--tests/fuzz/dict/uci.dict18
-rw-r--r--tests/fuzz/inputs/dhcp49
-rw-r--r--tests/fuzz/inputs/firewall208
-rw-r--r--tests/fuzz/test-fuzz.c60
15 files changed, 359 insertions, 0 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 872ed6d..6f31b93 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,2 +1,6 @@
ADD_SUBDIRECTORY(cram)
ADD_SUBDIRECTORY(shunit2)
+
+IF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ ADD_SUBDIRECTORY(fuzz)
+ENDIF()
diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt
new file mode 100644
index 0000000..1533c46
--- /dev/null
+++ b/tests/fuzz/CMakeLists.txt
@@ -0,0 +1,18 @@
+FILE(GLOB test_cases "test-*.c")
+
+MACRO(ADD_FUZZER_TEST name)
+ ADD_EXECUTABLE(${name} ${name}.c)
+ TARGET_COMPILE_OPTIONS(${name} PRIVATE -g -O1 -fno-omit-frame-pointer -fsanitize=fuzzer,address,leak,undefined)
+ TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR})
+ TARGET_LINK_OPTIONS(${name} PRIVATE -stdlib=libc++ -fsanitize=fuzzer,address,leak,undefined)
+ TARGET_LINK_LIBRARIES(${name} uci)
+ ADD_TEST(
+ NAME ${name}
+ COMMAND ${name} -max_len=256 -timeout=10 -max_total_time=300 -dict=${CMAKE_CURRENT_SOURCE_DIR}/dict/uci.dict ${CMAKE_CURRENT_SOURCE_DIR}/corpus
+ )
+ENDMACRO(ADD_FUZZER_TEST)
+
+FOREACH(test_case ${test_cases})
+ GET_FILENAME_COMPONENT(test_case ${test_case} NAME_WE)
+ ADD_FUZZER_TEST(${test_case})
+ENDFOREACH(test_case)
diff --git a/tests/fuzz/corpus/231ee80a172b8e1749b9d91867989d88e4faf7bb b/tests/fuzz/corpus/231ee80a172b8e1749b9d91867989d88e4faf7bb
new file mode 100644
index 0000000..9c17457
--- /dev/null
+++ b/tests/fuzz/corpus/231ee80a172b8e1749b9d91867989d88e4faf7bb
Binary files differ
diff --git a/tests/fuzz/corpus/26a6253fc1eb695b61a2fc7640ee4c03c19e438e b/tests/fuzz/corpus/26a6253fc1eb695b61a2fc7640ee4c03c19e438e
new file mode 100644
index 0000000..4e71cf6
--- /dev/null
+++ b/tests/fuzz/corpus/26a6253fc1eb695b61a2fc7640ee4c03c19e438e
Binary files differ
diff --git a/tests/fuzz/corpus/29a6e206439d792afba5e8e9c1fdf55e65a1145d b/tests/fuzz/corpus/29a6e206439d792afba5e8e9c1fdf55e65a1145d
new file mode 100644
index 0000000..f065bd7
--- /dev/null
+++ b/tests/fuzz/corpus/29a6e206439d792afba5e8e9c1fdf55e65a1145d
Binary files differ
diff --git a/tests/fuzz/corpus/51045ac5401085f5727c6d3c1cac5f8cc32a2927 b/tests/fuzz/corpus/51045ac5401085f5727c6d3c1cac5f8cc32a2927
new file mode 100644
index 0000000..f47ebca
--- /dev/null
+++ b/tests/fuzz/corpus/51045ac5401085f5727c6d3c1cac5f8cc32a2927
@@ -0,0 +1 @@
+ # \ No newline at end of file
diff --git a/tests/fuzz/corpus/845dcf3f15f3c28235e6be148a690e7f03b07f65 b/tests/fuzz/corpus/845dcf3f15f3c28235e6be148a690e7f03b07f65
new file mode 100644
index 0000000..cf5c1b0
--- /dev/null
+++ b/tests/fuzz/corpus/845dcf3f15f3c28235e6be148a690e7f03b07f65
Binary files differ
diff --git a/tests/fuzz/corpus/bb589d0621e5472f470fa3425a234c74b1e202e8 b/tests/fuzz/corpus/bb589d0621e5472f470fa3425a234c74b1e202e8
new file mode 100644
index 0000000..ad2823b
--- /dev/null
+++ b/tests/fuzz/corpus/bb589d0621e5472f470fa3425a234c74b1e202e8
@@ -0,0 +1 @@
+' \ No newline at end of file
diff --git a/tests/fuzz/corpus/ea387894a296772f96706df8b999a52d9334c746 b/tests/fuzz/corpus/ea387894a296772f96706df8b999a52d9334c746
new file mode 100644
index 0000000..2a72a97
--- /dev/null
+++ b/tests/fuzz/corpus/ea387894a296772f96706df8b999a52d9334c746
Binary files differ
diff --git a/tests/fuzz/corpus/id:000000,sig:11,src:000001,op:flip1,pos:24 b/tests/fuzz/corpus/id:000000,sig:11,src:000001,op:flip1,pos:24
new file mode 100644
index 0000000..3f4e40d
--- /dev/null
+++ b/tests/fuzz/corpus/id:000000,sig:11,src:000001,op:flip1,pos:24
Binary files differ
diff --git a/tests/fuzz/corpus/id:000008,sig:11,src:000022,op:arith8,pos:42,val:+26 b/tests/fuzz/corpus/id:000008,sig:11,src:000022,op:arith8,pos:42,val:+26
new file mode 100644
index 0000000..20bc48d
--- /dev/null
+++ b/tests/fuzz/corpus/id:000008,sig:11,src:000022,op:arith8,pos:42,val:+26
Binary files differ
diff --git a/tests/fuzz/dict/uci.dict b/tests/fuzz/dict/uci.dict
new file mode 100644
index 0000000..73c86ec
--- /dev/null
+++ b/tests/fuzz/dict/uci.dict
@@ -0,0 +1,18 @@
+"c"
+"config"
+"p"
+"package"
+"o"
+"option"
+"l"
+"list"
+"'"
+"\""
+" "
+"\x00"
+"\x0a"
+"\x0d"
+"\x09"
+"#"
+";"
+"\\"
diff --git a/tests/fuzz/inputs/dhcp b/tests/fuzz/inputs/dhcp
new file mode 100644
index 0000000..2bc0d31
--- /dev/null
+++ b/tests/fuzz/inputs/dhcp
@@ -0,0 +1,49 @@
+
+config dnsmasq
+ option domainneeded '1'
+ option boguspriv '1'
+ option filterwin2k '0'
+ option localise_queries '1'
+ option rebind_protection '1'
+ option rebind_localhost '1'
+ option local '/lan/'
+ option domain 'lan'
+ option expandhosts '1'
+ option nonegcache '0'
+ option authoritative '1'
+ option readethers '1'
+ option leasefile '/tmp/dhcp.leases'
+ option resolvfile '/tmp/resolv.conf.d/resolv.conf.auto'
+ option nonwildcard '1'
+ option localservice '1'
+
+config dhcp 'lan'
+ option interface 'lan'
+ option start '100'
+ option limit '150'
+ option leasetime '12h'
+ option dhcpv6 'server'
+ option ra 'server'
+ option ra_slaac '1'
+ list ra_flags 'managed-config'
+ list ra_flags 'other-config'
+
+config dhcp 'wan'
+ option interface 'wan'
+ option ignore '1'
+
+config odhcpd 'odhcpd'
+ option maindhcp '0'
+ option leasefile '/tmp/hosts/odhcpd'
+ option leasetrigger '/usr/sbin/odhcpd-update'
+ option loglevel '4'
+
+config host
+ option name 'foo'
+ option ip '192.168.1.90'
+ option mac '20:de:ad:be:ef:99'
+
+config host
+ option name 'moo-ap01'
+ option ip '192.168.1.2'
+ option mac '00:dd:8d:f7:e6:6f'
diff --git a/tests/fuzz/inputs/firewall b/tests/fuzz/inputs/firewall
new file mode 100644
index 0000000..5e22f98
--- /dev/null
+++ b/tests/fuzz/inputs/firewall
@@ -0,0 +1,208 @@
+config defaults
+ option syn_flood 1
+ option input ACCEPT
+ option output ACCEPT
+ option forward REJECT
+# Uncomment this line to disable ipv6 rules
+# option disable_ipv6 1
+
+config zone
+ option name lan
+ list network 'lan'
+ option input ACCEPT
+ option output ACCEPT
+ option forward ACCEPT
+
+config zone
+ option name wan
+ list network 'wan'
+ list network 'wan6'
+ option input REJECT
+ option output ACCEPT
+ option forward REJECT
+ option masq 1
+ option mtu_fix 1
+
+config forwarding
+ option src lan
+ option dest wan
+
+# We need to accept udp packets on port 68,
+# see https://dev.openwrt.org/ticket/4108
+config rule
+ option name Allow-DHCP-Renew
+ option src wan
+ option proto udp
+ option dest_port 68
+ option target ACCEPT
+ option family ipv4
+
+# Allow IPv4 ping
+config rule
+ option name Allow-Ping
+ option src wan
+ option proto icmp
+ option icmp_type echo-request
+ option family ipv4
+ option target ACCEPT
+
+config rule
+ option name Allow-IGMP
+ option src wan
+ option proto igmp
+ option family ipv4
+ option target ACCEPT
+
+# Allow DHCPv6 replies
+# see https://dev.openwrt.org/ticket/10381
+config rule
+ option name Allow-DHCPv6
+ option src wan
+ option proto udp
+ option src_ip fc00::/6
+ option dest_ip fc00::/6
+ option dest_port 546
+ option family ipv6
+ option target ACCEPT
+
+config rule
+ option name Allow-MLD
+ option src wan
+ option proto icmp
+ option src_ip fe80::/10
+ list icmp_type '130/0'
+ list icmp_type '131/0'
+ list icmp_type '132/0'
+ list icmp_type '143/0'
+ option family ipv6
+ option target ACCEPT
+
+# Allow essential incoming IPv6 ICMP traffic
+config rule
+ option name Allow-ICMPv6-Input
+ option src wan
+ option proto icmp
+ list icmp_type echo-request
+ list icmp_type echo-reply
+ list icmp_type destination-unreachable
+ list icmp_type packet-too-big
+ list icmp_type time-exceeded
+ list icmp_type bad-header
+ list icmp_type unknown-header-type
+ list icmp_type router-solicitation
+ list icmp_type neighbour-solicitation
+ list icmp_type router-advertisement
+ list icmp_type neighbour-advertisement
+ option limit 1000/sec
+ option family ipv6
+ option target ACCEPT
+
+# Allow essential forwarded IPv6 ICMP traffic
+config rule
+ option name Allow-ICMPv6-Forward
+ option src wan
+ option dest *
+ option proto icmp
+ list icmp_type echo-request
+ list icmp_type echo-reply
+ list icmp_type destination-unreachable
+ list icmp_type packet-too-big
+ list icmp_type time-exceeded
+ list icmp_type bad-header
+ list icmp_type unknown-header-type
+ option limit 1000/sec
+ option family ipv6
+ option target ACCEPT
+
+config rule
+ option name Allow-IPSec-ESP
+ option src wan
+ option dest lan
+ option proto esp
+ option target ACCEPT
+
+config rule
+ option name Allow-ISAKMP
+ option src wan
+ option dest lan
+ option dest_port 500
+ option proto udp
+ option target ACCEPT
+
+# allow interoperability with traceroute classic
+# note that traceroute uses a fixed port range, and depends on getting
+# back ICMP Unreachables. if we're operating in DROP mode, it won't
+# work so we explicitly REJECT packets on these ports.
+config rule
+ option name Support-UDP-Traceroute
+ option src wan
+ option dest_port 33434:33689
+ option proto udp
+ option family ipv4
+ option target REJECT
+ option enabled false
+
+# include a file with users custom iptables rules
+config include
+ option path /etc/firewall.user
+
+
+### EXAMPLE CONFIG SECTIONS
+# do not allow a specific ip to access wan
+#config rule
+# option src lan
+# option src_ip 192.168.45.2
+# option dest wan
+# option proto tcp
+# option target REJECT
+
+# block a specific mac on wan
+#config rule
+# option dest wan
+# option src_mac 00:11:22:33:44:66
+# option target REJECT
+
+# block incoming ICMP traffic on a zone
+#config rule
+# option src lan
+# option proto ICMP
+# option target DROP
+
+# port redirect port coming in on wan to lan
+#config redirect
+# option src wan
+# option src_dport 80
+# option dest lan
+# option dest_ip 192.168.16.235
+# option dest_port 80
+# option proto tcp
+
+# port redirect of remapped ssh port (22001) on wan
+#config redirect
+# option src wan
+# option src_dport 22001
+# option dest lan
+# option dest_port 22
+# option proto tcp
+
+### FULL CONFIG SECTIONS
+#config rule
+# option src lan
+# option src_ip 192.168.45.2
+# option src_mac 00:11:22:33:44:55
+# option src_port 80
+# option dest wan
+# option dest_ip 194.25.2.129
+# option dest_port 120
+# option proto tcp
+# option target REJECT
+
+#config redirect
+# option src lan
+# option src_ip 192.168.45.2
+# option src_mac 00:11:22:33:44:55
+# option src_port 1024
+# option src_dport 80
+# option dest_ip 194.25.2.129
+# option dest_port 120
+# option proto tcp
diff --git a/tests/fuzz/test-fuzz.c b/tests/fuzz/test-fuzz.c
new file mode 100644
index 0000000..9946a57
--- /dev/null
+++ b/tests/fuzz/test-fuzz.c
@@ -0,0 +1,60 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "uci.h"
+
+static void fuzz_uci_import(const uint8_t *input, size_t size)
+{
+ int r;
+ int fd;
+ FILE *fs = NULL;
+ struct uci_context *ctx = NULL;
+ struct uci_package *package = NULL;
+
+ fd = open("/dev/shm", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ perror("unable to create temp file");
+ exit(-1);
+ }
+
+ r = write(fd, input, size);
+ if (r < 0) {
+ perror("unable to write()");
+ exit(-1);
+ }
+
+ fs = fdopen(fd, "r");
+ if (fs == NULL) {
+ perror("unable to fdopen()");
+ exit(-1);
+ }
+
+ fseek(fs, 0L, SEEK_SET);
+
+ ctx = uci_alloc_context();
+ if (ctx == NULL) {
+ perror("unable to uci_alloc_context()");
+ exit(-1);
+ }
+
+ uci_import(ctx, fs, NULL, &package, false);
+ uci_free_context(ctx);
+ close(fd);
+ fclose(fs);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t size)
+{
+ fuzz_uci_import(input, size);
+ return 0;
+}