Coverage Report

Created: 2025-11-24 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/testing/fuzzing/snmp_agent_e2e_fuzzer.c
Line
Count
Source
1
 /*
2
  * Copyright (c) 2021, Net-snmp authors
3
  * All rights reserved.
4
  *
5
  * Redistribution and use in source and binary forms, with or without
6
  * modification, are permitted provided that the following conditions are met:
7
  *
8
  * * Redistributions of source code must retain the above copyright notice, this
9
  *   list of conditions and the following disclaimer.
10
  *
11
  * * Redistributions in binary form must reproduce the above copyright notice,
12
  *   this list of conditions and the following disclaimer in the documentation
13
  *   and/or other materials provided with the distribution.
14
  *
15
  * * Neither the name of the copyright holder nor the names of its
16
  *   contributors may be used to endorse or promote products derived from
17
  *   this software without specific prior written permission.
18
  *
19
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
  */
30
#include <assert.h>
31
#include <net-snmp/net-snmp-config.h>
32
#include <net-snmp/net-snmp-includes.h>
33
#include <net-snmp/agent/net-snmp-agent-includes.h>
34
#include <net-snmp/agent/mib_modules.h>
35
#include <unistd.h>
36
#include "ada_fuzz_header.h"
37
38
int
39
LLVMFuzzerInitialize(int *argc, char ***argv)
40
32
{
41
32
    if (getenv("NETSNMP_DEBUGGING") != NULL) {
42
        /*
43
         * Turn on all debugging, to help understand what
44
         * bits of the parser are running.
45
         */
46
0
        snmp_enable_stderrlog();
47
0
        snmp_set_do_debugging(1);
48
0
        debug_register_tokens("");
49
0
    }
50
51
32
    setenv("MIBDIRS", "/tmp/", 1);
52
32
    return 0;
53
32
}
54
55
static int free_session_impl(int majorID, int minorID,
56
                             netsnmp_agent_session *freed_session,
57
                             netsnmp_agent_session **this_session)
58
12.7k
{
59
12.7k
    if (*this_session == freed_session) {
60
12.7k
        fprintf(stderr, "%s(%#lx)\n", __func__, (uintptr_t)freed_session);
61
12.7k
        *this_session = NULL;
62
12.7k
    }
63
12.7k
    return 0;
64
12.7k
}
65
66
static int free_session(int majorID, int minorID, void *serverarg,
67
                        void *clientarg)
68
12.7k
{
69
12.7k
    return free_session_impl(majorID, minorID, serverarg, clientarg);
70
12.7k
}
71
72
int
73
LLVMFuzzerTestOneInput(const uint8_t * data, size_t size)
74
3.20k
{
75
3.20k
    af_gb_init();
76
77
    /*
78
     * Extract the fuzz data. We do this early to avoid overhead
79
     * from initializing the agent and then having to exit due to
80
     * limited fuzz data. 
81
     */
82
3.20k
    char           *mib_file_data =
83
3.20k
        af_gb_get_null_terminated(&data, &size);
84
3.20k
    char           *pdu1_content = af_gb_get_null_terminated(&data, &size);
85
3.20k
    char           *pdu2_content = af_gb_get_null_terminated(&data, &size);
86
3.20k
    char           *pdu3_content = af_gb_get_null_terminated(&data, &size);
87
3.20k
    char           *pdu4_content = af_gb_get_null_terminated(&data, &size);
88
89
90
3.20k
    char           *pdu_arrs[4] =
91
3.20k
        { pdu1_content, pdu2_content, pdu3_content, pdu4_content };
92
3.20k
    if (mib_file_data != NULL && pdu1_content != NULL
93
3.19k
        && pdu2_content != NULL && pdu3_content != NULL
94
3.18k
        && pdu4_content != NULL) {
95
        /*
96
         * Create a file with random data from the fuzzer and
97
         * add it as a mib file.
98
         */
99
3.18k
        char            filename[256];
100
3.18k
        sprintf(filename, "/tmp/libfuzzer.%d", getpid());
101
3.18k
        FILE           *fp = fopen(filename, "wb");
102
3.18k
        if (!fp) {
103
0
            af_gb_cleanup();
104
0
            return 0;
105
0
        }
106
3.18k
        fwrite(mib_file_data, strlen(mib_file_data), 1, fp);
107
3.18k
        fclose(fp);
108
109
3.18k
        init_agent("snmpd");
110
3.18k
        add_mibfile(filename, "not-used");
111
112
3.18k
        init_snmp("snmpd");
113
3.18k
        char           *no_smux = strdup("!smux");
114
3.18k
        add_to_init_list(no_smux);
115
3.18k
        init_master_agent();
116
117
        /*
118
         * Handle 4 PDUs initialised based on fuzzer data
119
         */
120
15.9k
        for (int i = 0; i < 4; i++) {
121
            /*
122
             * Create a PDU based on parsing fuzz data
123
             */
124
12.7k
            size_t          bytes_remaining = strlen(pdu_arrs[i]);
125
12.7k
            netsnmp_pdu    *pdu = SNMP_MALLOC_TYPEDEF(netsnmp_pdu);
126
12.7k
            snmp_pdu_parse(pdu, (unsigned char *) pdu_arrs[i],
127
12.7k
                           &bytes_remaining);
128
12.7k
            pdu->flags |= UCD_MSG_FLAG_ALWAYS_IN_VIEW;
129
130
            /*
131
             * Create a agent snmp session and handle the snmp packet
132
             */
133
12.7k
            netsnmp_session sess = { };
134
12.7k
            netsnmp_agent_session *vals =
135
12.7k
                init_agent_snmp_session(&sess, pdu);
136
137
12.7k
            snmp_register_callback(SNMP_CALLBACK_APPLICATION,
138
12.7k
                                   SNMP_CALLBACK_FREE_SESSION,
139
12.7k
                                   free_session, &vals);
140
141
12.7k
            handle_snmp_packet(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE, &sess, 0,
142
12.7k
                               pdu, vals);
143
12.7k
            snmp_free_pdu(pdu);
144
            /*
145
             * handle_snmp_packet() may free the session 'vals'. If
146
             * handle_snmp_packet() freed 'vals', 'vals' will be NULL.
147
             * free_agent_snmp_session() ignores NULL pointers.
148
             */
149
12.7k
            free_agent_snmp_session(vals);
150
12.7k
            int count;
151
12.7k
            count = snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
152
12.7k
                                             SNMP_CALLBACK_FREE_SESSION,
153
12.7k
                                             free_session, &vals, TRUE);
154
12.7k
            assert(count == 1);
155
12.7k
        }
156
157
3.18k
        shutdown_master_agent();
158
3.18k
        snmp_shutdown("snmpd");
159
3.18k
        shutdown_agent();
160
161
        /*
162
         * Cleanup the file
163
         */
164
3.18k
        unlink(filename);
165
3.18k
        free(no_smux);
166
3.18k
    }
167
168
3.20k
    af_gb_cleanup();
169
3.20k
    return 0;
170
3.20k
}