From: Bhargava Shastry <[email protected]> This patch adds a new target called ofctl_parse_target to ossfuzz. The main idea is to begin to fuzz APIs from the ofctl utility program. At a later point, these may be added. For the moment, this patch only fuzzes APIs that parse flow mod commands.
This target is demonstrably capable of finding memory corruption defects in the parsing path. To aid the fuzzing process, a dictionary file containing tokens specific to this parsing path have been added. Signed-off-by: Bhargava Shastry <[email protected]> --- tests/oss-fuzz/automake.mk | 13 ++- .../config/ofctl_parse_target.options | 3 + tests/oss-fuzz/config/ofp-flow.dict | 45 ++++++++ tests/oss-fuzz/ofctl_parse_target.c | 106 ++++++++++++++++++ 4 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 tests/oss-fuzz/config/ofctl_parse_target.options create mode 100644 tests/oss-fuzz/config/ofp-flow.dict create mode 100644 tests/oss-fuzz/ofctl_parse_target.c diff --git a/tests/oss-fuzz/automake.mk b/tests/oss-fuzz/automake.mk index 2c506be3d..5bf7d0d7c 100644 --- a/tests/oss-fuzz/automake.mk +++ b/tests/oss-fuzz/automake.mk @@ -4,7 +4,8 @@ OSS_FUZZ_TARGETS = \ tests/oss-fuzz/ofp_print_target \ tests/oss-fuzz/expr_parse_target \ tests/oss-fuzz/odp_target \ - tests/oss-fuzz/miniflow_target + tests/oss-fuzz/miniflow_target \ + tests/oss-fuzz/ofctl_parse_target EXTRA_PROGRAMS += $(OSS_FUZZ_TARGETS) oss-fuzz-targets: $(OSS_FUZZ_TARGETS) @@ -45,6 +46,12 @@ tests_oss_fuzz_miniflow_target_SOURCES = \ tests_oss_fuzz_miniflow_target_LDADD = lib/libopenvswitch.la tests_oss_fuzz_miniflow_target_LDFLAGS = $(LIB_FUZZING_ENGINE) -lc++ +tests_oss_fuzz_ofctl_parse_target_SOURCES = \ + tests/oss-fuzz/ofctl_parse_target.c \ + tests/oss-fuzz/fuzzer.h +tests_oss_fuzz_ofctl_parse_target_LDADD = lib/libopenvswitch.la +tests_oss_fuzz_ofctl_parse_target_LDFLAGS = $(LIB_FUZZING_ENGINE) -lc++ + EXTRA_DIST += \ tests/oss-fuzz/config/flow_extract_target.options \ tests/oss-fuzz/config/json_parser_target.options \ @@ -52,6 +59,8 @@ EXTRA_DIST += \ tests/oss-fuzz/config/expr_parse_target.options \ tests/oss-fuzz/config/odp_target.options \ tests/oss-fuzz/config/miniflow_target.options \ + tests/oss-fuzz/config/ofctl_parse_target.options \ tests/oss-fuzz/config/ovs.dict \ tests/oss-fuzz/config/expr.dict \ - tests/oss-fuzz/config/odp.dict \ No newline at end of file + tests/oss-fuzz/config/odp.dict \ + tests/oss-fuzz/config/ofp-flow.dict diff --git a/tests/oss-fuzz/config/ofctl_parse_target.options b/tests/oss-fuzz/config/ofctl_parse_target.options new file mode 100644 index 000000000..6d67dd6ad --- /dev/null +++ b/tests/oss-fuzz/config/ofctl_parse_target.options @@ -0,0 +1,3 @@ +[libfuzzer] +close_fd_mask = 3 +dict = ofp-flow.dict diff --git a/tests/oss-fuzz/config/ofp-flow.dict b/tests/oss-fuzz/config/ofp-flow.dict new file mode 100644 index 000000000..01175e5eb --- /dev/null +++ b/tests/oss-fuzz/config/ofp-flow.dict @@ -0,0 +1,45 @@ +")" +"(" +"[" +"]" +"," +"-" +"0" +":" +"=" +"ADD" +"DEL" +"DEL_STRICT" +"MOD" +"MOD_STRICT" +"\x00" +"\x20" +"\x3F" +"actions" +"add" +"allow_hidden_fields" +"cc" +"check_overlap" +"cookie" +"delete" +"delete_strict" +"duration" +"eth" +"hard_age" +"hard_timeout" +"idle_age" +"idle_timeout" +"importance" +"modify" +"modify_strict" +"n_bytes" +"n_packets" +"no_byte_counts" +"no_packet_counts" +"no_readonly_table" +"out_group" +"out_port" +"priority" +"reset_counts" +"send_flow_rem" +"table" diff --git a/tests/oss-fuzz/ofctl_parse_target.c b/tests/oss-fuzz/ofctl_parse_target.c new file mode 100644 index 000000000..29f89f9b5 --- /dev/null +++ b/tests/oss-fuzz/ofctl_parse_target.c @@ -0,0 +1,106 @@ +#include <config.h> +#include "fuzzer.h" +#include "openvswitch/ofp-flow.h" +#include "ofp-version-opt.h" +#include "ofproto/ofproto.h" +#include "openflow/openflow.h" +#include "openvswitch/ofpbuf.h" +#include "openvswitch/vlog.h" +#include "util.h" + +static void +ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms, + enum ofputil_protocol usable_protocols) +{ + enum ofputil_protocol protocol = 0; + char *usable_s; + size_t i; + + usable_s = ofputil_protocols_to_string(usable_protocols); + printf("usable protocols: %s\n", usable_s); + free(usable_s); + + if (!(usable_protocols & OFPUTIL_P_ANY)) { + printf("no usable protocol\n"); + } + for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) { + protocol = 1 << i; + if (protocol & usable_protocols & OFPUTIL_P_ANY) { + break; + } + } + ovs_assert(is_pow2(protocol)); + + printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol)); + + for (i = 0; i < n_fms; i++) { + struct ofputil_flow_mod *fm = &fms[i]; + struct ofpbuf *msg; + + msg = ofputil_encode_flow_mod(fm, protocol); + ofpbuf_delete(msg); + + free(CONST_CAST(struct ofpact *, fm->ofpacts)); + minimatch_destroy(&fm->match); + } +} + +/* "parse-flow FLOW": parses the argument as a flow (like add-flow) and prints + * it back to stdout. */ +static void +ofctl_parse_flow(const char *input, int command) +{ + enum ofputil_protocol usable_protocols; + struct ofputil_flow_mod fm; + char *error; + + error = parse_ofp_flow_mod_str(&fm, input, NULL, NULL, + command, &usable_protocols); + if (error) { + printf("Error encountered: %s\n", error); + } + ofctl_parse_flows__(&fm, 1, usable_protocols); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Bail out if we cannot construct at least a 1 char string. + * Reserve 1 byte to decide flow mod command. + * + * Here's the structure of data we expect + * |--Byte 1--|--Byte 2--|...|--Byte (size-1)--| + * + * where, + * + * Byte 1: Used to decide which ofp flow mod command to test + * Bytes 2--(size-1): The C string that is actually passed to + * ofctl_parse_flow() test API. + * + * This means that the fuzzed input is actually a C string of + * length = (size -2) with the terminal byte being the NUL + * character. Moreover, this string is expected to not contain + * a new-line character. + */ + const char *stream = (const char *) data; + if (size < 3 || stream[size - 1] != '\0' || strchr(&stream[1], '\n') || + strlen(&stream[1]) != size - 2) { + return 0; + } + + /* Disable logging to avoid write to disk. */ + static bool isInit = false; + if (!isInit) { + vlog_set_verbosity("off"); + isInit = true; + } + + /* Decide test parameters using first byte of fuzzed input. */ + int command = (stream[0] % OFPFC_DELETE_STRICT) + 1; + + /* Fuzz extended match parsing. */ + const char *input = &stream[1]; + ofctl_parse_flow(input, command); + + return 0; +} -- 2.17.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
