Coverage Report

Created: 2026-04-12 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openvswitch/tests/oss-fuzz/ofctl_parse_target.c
Line
Count
Source
1
#include <config.h>
2
#include "fuzzer.h"
3
#include "openvswitch/ofp-flow.h"
4
#include "ofp-version-opt.h"
5
#include "ofproto/ofproto.h"
6
#include "openflow/openflow.h"
7
#include "openvswitch/ofpbuf.h"
8
#include "openvswitch/vlog.h"
9
#include "util.h"
10
11
static void
12
ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms,
13
                    enum ofputil_protocol usable_protocols)
14
8.70k
{
15
8.70k
    enum ofputil_protocol protocol = 0;
16
8.70k
    char *usable_s;
17
8.70k
    size_t i;
18
19
8.70k
    usable_s = ofputil_protocols_to_string(usable_protocols);
20
8.70k
    printf("usable protocols: %s\n", usable_s);
21
8.70k
    free(usable_s);
22
23
8.70k
    if (!(usable_protocols & OFPUTIL_P_ANY)) {
24
202
        printf("no usable protocol\n");
25
202
        goto free;
26
202
    }
27
18.7k
    for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
28
18.7k
        protocol = 1u << i;
29
18.7k
        if (protocol & usable_protocols & OFPUTIL_P_ANY) {
30
8.50k
            break;
31
8.50k
        }
32
18.7k
    }
33
8.50k
    ovs_assert(is_pow2(protocol));
34
35
8.50k
    printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol));
36
37
17.0k
    for (i = 0; i < n_fms; i++) {
38
8.50k
        struct ofputil_flow_mod *fm = &fms[i];
39
8.50k
        struct ofpbuf *msg;
40
41
8.50k
        msg = ofputil_encode_flow_mod(fm, protocol);
42
8.50k
        ofpbuf_delete(msg);
43
8.50k
    }
44
45
8.70k
free:
46
17.4k
    for (i = 0; i < n_fms; i++) {
47
8.70k
        struct ofputil_flow_mod *fm = &fms[i];
48
8.70k
        free(CONST_CAST(struct ofpact *, fm->ofpacts));
49
8.70k
        minimatch_destroy(&fm->match);
50
8.70k
    }
51
8.70k
}
52
53
/* "parse-flow FLOW": parses the argument as a flow (like add-flow) and prints
54
 * it back to stdout.  */
55
static void
56
ofctl_parse_flow(const char *input, int command)
57
18.9k
{
58
18.9k
    enum ofputil_protocol usable_protocols;
59
18.9k
    struct ofputil_flow_mod fm;
60
18.9k
    char *error;
61
62
18.9k
    error = parse_ofp_flow_mod_str(&fm, input, NULL, NULL,
63
18.9k
                                   command, &usable_protocols);
64
18.9k
    if (error) {
65
10.2k
        printf("Error encountered: %s\n", error);
66
10.2k
        free(error);
67
10.2k
    } else {
68
8.70k
        ofctl_parse_flows__(&fm, 1, usable_protocols);
69
8.70k
    }
70
18.9k
}
71
72
int
73
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
74
35.2k
{
75
    /* Bail out if we cannot construct at least a 1 char string.
76
     * Reserve 1 byte to decide flow mod command.
77
     *
78
     * Here's the structure of data we expect
79
     * |--Byte 1--|--Byte 2--|...|--Byte (size-1)--|
80
     *
81
     * where,
82
     *
83
     * Byte 1: Used to decide which ofp flow mod command to test
84
     * Bytes 2--(size-1): The C string that is actually passed to
85
     *                    ofctl_parse_flow() test API.
86
     *
87
     * This means that the fuzzed input is actually a C string of
88
     * length = (size -2) with the terminal byte being the NUL
89
     * character. Moreover, this string is expected to not contain
90
     * a new-line character.
91
     */
92
35.2k
    const char *stream = (const char *) data;
93
35.2k
    if (size < 3 || stream[size - 1] != '\0' || strchr(&stream[1], '\n') ||
94
35.1k
        strlen(&stream[1]) != size - 2) {
95
43
        return 0;
96
43
    }
97
98
    /* Disable logging to avoid write to disk. */
99
35.1k
    static bool isInit = false;
100
35.1k
    if (!isInit) {
101
2
        vlog_set_verbosity("off");
102
2
        isInit = true;
103
2
    }
104
105
    /* Decide test parameters using first byte of fuzzed input. */
106
35.1k
    int command = (stream[0] % OFPFC_DELETE_STRICT) + 1;
107
108
    /* Fuzz extended match parsing. */
109
35.1k
    const char *input = &stream[1];
110
35.1k
    ofctl_parse_flow(input, command);
111
112
35.1k
    return 0;
113
35.2k
}