Skip to content

Commit

Permalink
ossfuzz: Additions for new ODP parser target
Browse files Browse the repository at this point in the history
This patch adds a new oss-fuzz target for the ODP
 parser. The target harness has been adapted from test-odp.c. Prominently, it
 leaves out "parse_filter" due to an  unresolvable bug in that code at the
 time of writing.

It also includes the following:
  - a fuzzing dictionary
  - fuzzing config
  - some automake additions for the new target

Signed-off-by: Bhargava Shastry <bshastry@sect.tu-berlin.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
  • Loading branch information
bshastry authored and blp committed Oct 3, 2018
1 parent 7837818 commit ea43b02
Show file tree
Hide file tree
Showing 4 changed files with 331 additions and 2 deletions.
13 changes: 11 additions & 2 deletions tests/oss-fuzz/automake.mk
Expand Up @@ -2,7 +2,8 @@ OSS_FUZZ_TARGETS = \
tests/oss-fuzz/flow_extract_target \
tests/oss-fuzz/json_parser_target \
tests/oss-fuzz/ofp_print_target \
tests/oss-fuzz/expr_parse_target
tests/oss-fuzz/expr_parse_target \
tests/oss-fuzz/odp_target
EXTRA_PROGRAMS += $(OSS_FUZZ_TARGETS)
oss-fuzz-targets: $(OSS_FUZZ_TARGETS)

Expand Down Expand Up @@ -31,10 +32,18 @@ tests_oss_fuzz_expr_parse_target_LDADD = lib/libopenvswitch.la \
ovn/lib/libovn.la
tests_oss_fuzz_expr_parse_target_LDFLAGS = $(LIB_FUZZING_ENGINE) -lc++

tests_oss_fuzz_odp_target_SOURCES = \
tests/oss-fuzz/odp_target.c \
tests/oss-fuzz/fuzzer.h
tests_oss_fuzz_odp_target_LDADD = lib/libopenvswitch.la
tests_oss_fuzz_odp_target_LDFLAGS = $(LIB_FUZZING_ENGINE) -lc++

EXTRA_DIST += \
tests/oss-fuzz/config/flow_extract_target.options \
tests/oss-fuzz/config/json_parser_target.options \
tests/oss-fuzz/config/ofp_print_target.options \
tests/oss-fuzz/config/expr_parse_target.options \
tests/oss-fuzz/config/odp_target.options \
tests/oss-fuzz/config/ovs.dict \
tests/oss-fuzz/config/expr.dict
tests/oss-fuzz/config/expr.dict \
tests/oss-fuzz/config/odp.dict
170 changes: 170 additions & 0 deletions tests/oss-fuzz/config/odp.dict
@@ -0,0 +1,170 @@
"("
")"
","
"/0x"
"0x"
": "
"="
"=r"
"action"
"arp"
"bfd"
"bos"
"c1"
"c2"
"c3"
"c4"
"cc"
"cfi"
"cfm"
"class"
"clone"
"code"
"commit,"
"crit,"
"csum"
"ct"
"ct(error)"
"ct_clear"
"ct_label"
"ct_mark"
"ct_state"
"ct_tuple4"
"ct_tuple6"
"ct_zone"
"dir"
"dl_type"
"dnat"
"dp_hash"
"drop"
"dst"
"dst_port"
"egress"
"encap"
"error"
"erspan"
"erspan(ver=1,sid=0x,dir=,idx=0x)"
"est"
"eth"
"eth_type"
"eth_type(0/)"
"first"
"flags"
"force_commit,"
"frag"
"gbp("
"geneve"
"gre((flags=0x,proto=0x)"
"hash,"
"helper"
"hlimit"
"hwid"
"icmp"
"icmpv6"
"id"
"idx="
"in_port"
"ingress"
"inv"
"ip6erspan"
"ipfix(output_port="
"ipv4"
"ipv6"
"ipv6_dst"
"ipv6_src"
"l4()"
"label"
"lacp"
"later"
"len"
"lldp"
"mark=/,"
"match"
"md2"
"mdtype"
"meter()"
"mpls"
"nat"
"nd"
"new"
"no"
"np"
"ns"
"nsh"
"oam,"
"op"
"options("
"out_port("
"packet_type"
"pcp="
"persistent,"
"pop_eth"
"pop_mpls(eth_type=0x)"
"pop_nsh()"
"pop_vlan"
"proto"
"push_eth(src=:::::,dst=:::::,type=)"
"push_mpls("
"push_nsh("
"push_vlan("
"push_vlan(tpid=,vid=,pcp=,cfi=)"
"random,"
"recirc()"
"recirc_id"
"rel"
"rpl"
"sFlow(vid=,pcp=,output=)"
"sample"
"sctp"
"seq=0x"
"set("
"set(nsh("
"sha"
"si"
"sip"
"skb_mark"
"skb_priority"
"sll"
"slow_path"
"snat"
"spi"
"src"
"src_port"
"stp"
"sym_l4()"
"target"
"tc="
"tclass"
"tcp"
"tcp_flags"
"tha"
"tip"
"tll"
"tnl_pop("
"tnl_push(tnl_port("
"too_little"
"too_much"
"tos"
"tp_dst"
"tp_src"
"tpid=0x"
"trk"
"trunc()"
"ttl"
"tun_id"
"tunnel"
"tunnel_out_port"
"type"
"udp"
"unspec"
"userdata"
"userspace("
"userspace(error)"
"userspace(pid"
"ver"
"vid"
"vlan"
"vxlan"
"vxlan(flags=0x,vni=0x)"
"vxlan(gbp("
"zone"
3 changes: 3 additions & 0 deletions tests/oss-fuzz/config/odp_target.options
@@ -0,0 +1,3 @@
[libfuzzer]
close_fd_mask = 3
dict = odp.dict
147 changes: 147 additions & 0 deletions tests/oss-fuzz/odp_target.c
@@ -0,0 +1,147 @@
#include <config.h>
#include "fuzzer.h"
#undef NDEBUG
#include "odp-util.h"
#include <stdio.h>
#include "openvswitch/dynamic-string.h"
#include "flow.h"
#include "openvswitch/match.h"
#include "openvswitch/ofpbuf.h"
#include "util.h"
#include "openvswitch/ofp-flow.h"
#include "openvswitch/vlog.h"

static int
parse_keys(bool wc_keys, const char *in)
{
int exit_code = 0;

enum odp_key_fitness fitness;
struct ofpbuf odp_key;
struct ofpbuf odp_mask;
struct flow flow;
struct ds out;
int error;

/* Convert string to OVS DP key. */
ofpbuf_init(&odp_key, 0);
ofpbuf_init(&odp_mask, 0);
error = odp_flow_from_string(in, NULL,
&odp_key, &odp_mask);
if (error) {
printf("odp_flow_from_string: error\n");
goto next;
}

if (!wc_keys) {
struct odp_flow_key_parms odp_parms = {
.flow = &flow,
.support = {
.recirc = true,
.ct_state = true,
.ct_zone = true,
.ct_mark = true,
.ct_label = true,
.max_vlan_headers = SIZE_MAX,
},
};

/* Convert odp_key to flow. */
fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
switch (fitness) {
case ODP_FIT_PERFECT:
break;

case ODP_FIT_TOO_LITTLE:
printf("ODP_FIT_TOO_LITTLE: ");
break;

case ODP_FIT_TOO_MUCH:
printf("ODP_FIT_TOO_MUCH: ");
break;

case ODP_FIT_ERROR:
printf("odp_flow_key_to_flow: error\n");
goto next;
}
/* Convert cls_rule back to odp_key. */
ofpbuf_uninit(&odp_key);
ofpbuf_init(&odp_key, 0);
odp_flow_key_from_flow(&odp_parms, &odp_key);

if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
printf ("too long: %"PRIu32" > %d\n",
odp_key.size, ODPUTIL_FLOW_KEY_BYTES);
exit_code = 1;
}
}

/* Convert odp_key to string. */
ds_init(&out);
if (wc_keys) {
odp_flow_format(odp_key.data, odp_key.size,
odp_mask.data, odp_mask.size, NULL, &out, false);
} else {
odp_flow_key_format(odp_key.data, odp_key.size, &out);
}
puts(ds_cstr(&out));
ds_destroy(&out);

next:
ofpbuf_uninit(&odp_key);
ofpbuf_uninit(&odp_mask);

return exit_code;
}

static int
parse_actions(const char *in)
{
struct ofpbuf odp_actions;
struct ds out;
int error;

/* Convert string to OVS DP actions. */
ofpbuf_init(&odp_actions, 0);
error = odp_actions_from_string(in, NULL, &odp_actions);
if (error) {
printf("odp_actions_from_string: error\n");
goto next;
}

/* Convert odp_actions back to string. */
ds_init(&out);
format_odp_actions(&out, odp_actions.data, odp_actions.size, NULL);
puts(ds_cstr(&out));
ds_destroy(&out);

next:
ofpbuf_uninit(&odp_actions);
return 0;
}

int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
/* Bail out if we cannot construct at least a 1 char string. */
const char *input = (const char *) data;
if (size < 2 || input[size - 1] != '\0' || strchr(input, '\n')) {
return 0;
}

/* Disable logging to avoid write to disk. */
static bool isInit = false;
if (!isInit) {
vlog_set_verbosity("off");
isInit = true;
}

/* Parse keys and wc keys. */
parse_keys(false, input);
parse_keys(true, input);

/* Parse actions. */
parse_actions(input);

return 0;
}

0 comments on commit ea43b02

Please sign in to comment.