1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#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");
goto free;
}
for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
protocol = 1u << 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:
for (i = 0; i < n_fms; i++) {
struct ofputil_flow_mod *fm = &fms[i];
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);
free(error);
} else {
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;
}
|