Coverage Report

Created: 2025-07-11 07:06

/src/rtpproxy/scripts/fuzz/fuzz_rtp_session.c
Line
Count
Source (jump to first uncovered line)
1
#include <sys/types.h>
2
#include <sys/socket.h>
3
#include <netinet/in.h>
4
#include <arpa/inet.h>
5
#include <assert.h>
6
#include <semaphore.h>
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <string.h>
10
11
#include "fuzz_standalone.h"
12
13
#define HAVE_CONFIG_H 1
14
#include "config_pp.h"
15
16
#include "rtpp_types.h"
17
#include "rtpp_cfg.h"
18
#include "rtp.h"
19
#include "rtpp_time.h"
20
#include "rtpp_codeptr.h"
21
#include "rtp_packet.h"
22
#include "rtpp_session.h"
23
#include "rtpp_pipe.h"
24
#include "rtpp_proc.h"
25
#include "rtpp_network.h"
26
#include "rtpp_stream.h"
27
#include "rtpp_ttl.h"
28
#include "rtpp_codeptr.h"
29
#include "rtpp_refcnt.h"
30
#include "rtpp_command.h"
31
#include "rtpp_weakref.h"
32
#include "rtpp_hash_table.h"
33
#include "advanced/packet_processor.h"
34
#include "advanced/pproc_manager.h"
35
36
#include "rfz_chunk.h"
37
#include "rfz_utils.h"
38
#include "rfz_command.h"
39
40
static struct {
41
    sem_t wi_proc_done;
42
} fuzz_ctx;
43
44
static void
45
fuzz_ctx_dtor(void)
46
2
{
47
2
    ExecuteRTPPCommand(&gconf, "X", 1, 0);
48
2
    sem_destroy(&fuzz_ctx.wi_proc_done);
49
2
}
50
51
static const char * const setup_script[] = {
52
    #include "fuzz_rtp_session.setup"
53
    NULL
54
};
55
56
static int
57
ExecuteScript(void)
58
3.70k
{
59
3.70k
    char line[RTPP_CMD_BUFLEN];
60
61
33.3k
    for (int i = 0; setup_script[i] != NULL; i++) {
62
29.6k
        const char *cp = setup_script[i];
63
29.6k
        int size = strlen(cp);
64
29.6k
        memcpy(line, cp, size + 1);
65
29.6k
        int r = ExecuteRTPPCommand(&gconf, line, size, 0);
66
29.6k
        if (r != 0)
67
0
            return (-1);
68
29.6k
    }
69
3.70k
    return (0);
70
3.70k
}
71
72
int
73
LLVMFuzzerInitialize(int *_argc, char ***_argv)
74
2
{
75
2
    RTPPInitializeParams.ttl = "60";
76
2
    int r = RTPPInitialize();
77
78
2
    if (r != 0)
79
0
        goto e0;
80
2
    if (sem_init(&fuzz_ctx.wi_proc_done, 0, 0) != 0)
81
0
        goto e0;
82
2
    if (ExecuteScript() != 0)
83
0
        goto e1;
84
2
    if (ExecuteRTPPCommand(&gconf, "X", 1, 0) != 0)
85
0
        goto e1;
86
2
    atexit(fuzz_ctx_dtor);
87
2
    return (0);
88
0
e1:
89
0
    sem_destroy(&fuzz_ctx.wi_proc_done);
90
0
e0:
91
0
    return (-1);
92
0
}
93
94
struct foreach_args {
95
    const char *data;
96
    size_t size;
97
    struct rtpp_proc_rstats *rsp;
98
    int nwait;
99
};
100
101
static void
102
wi_proc_complete(void *arg)
103
337k
{
104
337k
    sem_post(&fuzz_ctx.wi_proc_done);
105
337k
}
106
107
static int
108
proc_foreach(void *dp, void *ap)
109
168k
{
110
168k
    struct foreach_args *fap;
111
168k
    const struct rtpp_session *sp;
112
168k
    rtpp_refcnt_dtor_t wpd_f = (rtpp_refcnt_dtor_t)&wi_proc_complete;
113
114
168k
    fap = (struct foreach_args *)ap;
115
    /*
116
     * This method does not need us to bump ref, since we are in the
117
     * locked context of the rtpp_hash_table, which holds its own ref.
118
     */
119
168k
    sp = (const struct rtpp_session *)dp;
120
121
506k
    for (int i=0; i < 2; i++) {
122
337k
        struct sockaddr *rap;
123
337k
        struct rtp_packet *pktp = rtp_packet_alloc();
124
337k
        assert (pktp != NULL);
125
337k
        void *olddata = CALL_SMETHOD(pktp->rcnt, getdata);
126
337k
        CALL_SMETHOD(pktp->rcnt, attach, wpd_f, olddata);
127
337k
        rap = sstosa(&pktp->raddr);
128
337k
        memcpy(rap, fap->data, sizeof(struct sockaddr_in));
129
337k
        rap->sa_family = AF_INET;
130
337k
        pktp->size = fap->size - sizeof(struct sockaddr_in);
131
337k
        memcpy(pktp->data.buf, fap->data + sizeof(struct sockaddr_in), pktp->size);
132
337k
        struct rtpp_stream *istp = sp->rtp->stream[i],
133
337k
                           *ostp = sp->rtp->stream[i ^ 1];
134
337k
        struct pkt_proc_ctx pktx = {.strmp_in = istp,
135
337k
                                    .strmp_out = ostp,
136
337k
                                    .rsp = fap->rsp,
137
337k
                                    .pktp = pktp};
138
337k
        CALL_SMETHOD(istp->pproc_manager, handleat, &pktx, _PPROC_ORD_EMPTY);
139
337k
        fap->nwait += 1;
140
337k
    }
141
168k
    return (RTPP_HT_MATCH_CONT);
142
168k
}
143
144
int
145
LLVMFuzzerTestOneInput(const char *data, size_t size)
146
3.70k
{
147
3.70k
    static struct rtpp_proc_rstats rs = {0};
148
3.70k
    sem_t *wpdp = &fuzz_ctx.wi_proc_done;
149
3.70k
    struct {
150
3.70k
        union {
151
3.70k
            struct {
152
3.70k
                uint8_t reseed:1;
153
3.70k
            };
154
3.70k
            uint8_t value;
155
3.70k
        };
156
3.70k
    } op_flags;
157
158
3.70k
    if (size < 2)
159
1
        return (0);
160
161
3.70k
    op_flags.value = data[0];
162
3.70k
    data += 1;
163
3.70k
    size -= 1;
164
165
3.70k
    if (op_flags.reseed) {
166
1.31k
        SeedRNGs();
167
1.31k
    }
168
169
3.70k
    assert(ExecuteScript() == 0);
170
171
3.70k
    struct rfz_chunk chunk = {.rem_size = size, .rem_data = data};
172
3.70k
    struct foreach_args fa = {.rsp = &rs};
173
174
34.2k
    do {
175
34.2k
        chunk = rfz_get_chunk(chunk.rem_data, chunk.rem_size);
176
34.2k
        if (chunk.size < sizeof(struct sockaddr_in))
177
419
            break;
178
33.7k
        if (chunk.size > sizeof(struct sockaddr_in) + MAX_RPKT_LEN)
179
0
            break;
180
33.7k
        fa.data = chunk.data;
181
33.7k
        fa.size = chunk.size;
182
33.7k
        CALL_SMETHOD(gconf.cfsp->sessions_ht, foreach, proc_foreach, (void *)&fa, NULL);
183
33.7k
    } while (chunk.rem_size > 1);
184
341k
    for (int i = 0; i < fa.nwait; i++)
185
337k
        sem_wait(wpdp);
186
187
3.70k
    assert(ExecuteRTPPCommand(&gconf, "X", 1, 0) == 0);
188
3.70k
    return (0);
189
3.70k
}