Coverage Report

Created: 2025-07-11 06:42

/src/libhtp/test/fuzz/fuzz_htp.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file
3
 * @author Philippe Antoine <contact@catenacyber.fr>
4
 * fuzz harness for libhtp
5
 */
6
7
8
#include <errno.h>
9
#include <stdlib.h>
10
#include <sys/types.h>
11
#include <string.h>
12
#include <stdio.h>
13
#include <inttypes.h>
14
#include <sys/stat.h>
15
#include <fcntl.h>
16
17
#include "htp/htp.h"
18
#include "test/test.h"
19
#include "fuzz_htp.h"
20
21
FILE * logfile = NULL;
22
23
24
/**
25
 * Invoked at the end of every transaction. 
26
 *
27
 * @param[in] connp
28
 */
29
34.6k
static int HTPCallbackResponse(htp_tx_t *out_tx) {
30
34.6k
    if (out_tx != NULL) {
31
34.6k
        char *x = bstr_util_strdup_to_c(out_tx->request_line);
32
34.6k
        fprintf(logfile, "HTPCallbackResponse %s\n", x);
33
34.6k
        free(x);
34
34.6k
    }
35
34.6k
    return 0;
36
34.6k
}
37
38
static int HTPCallbackRequestHeaderData(htp_tx_data_t *tx_data)
39
164k
{
40
164k
    fprintf(logfile, "HTPCallbackRequestHeaderData %"PRIuMAX"\n", (uintmax_t)tx_data->len);
41
164k
    if (tx_data->len > 0) {
42
163k
        fprintf(logfile, "HTPCallbackRequestHeaderData %x %x\n", tx_data->data[0], tx_data->data[(uintmax_t)tx_data->len-1]);
43
163k
    }
44
164k
    return 0;
45
164k
}
46
47
static int HTPCallbackResponseHeaderData(htp_tx_data_t *tx_data)
48
73.8k
{
49
73.8k
    fprintf(logfile, "HTPCallbackResponseHeaderData %"PRIuMAX"\n", (uintmax_t)tx_data->len);
50
73.8k
    if (tx_data->len > 0) {
51
68.6k
        fprintf(logfile, "HTPCallbackResponseHeaderData %x %x\n", tx_data->data[0], tx_data->data[(uintmax_t)tx_data->len-1]);
52
68.6k
    }
53
73.8k
    return 0;
54
73.8k
}
55
56
static int HTPCallbackRequestHasTrailer(htp_tx_t *tx)
57
1.26k
{
58
1.26k
    fprintf(logfile, "HTPCallbackRequestHasTrailer\n");
59
1.26k
    return 0;
60
1.26k
}
61
62
static int HTPCallbackResponseHasTrailer(htp_tx_t *tx)
63
1.30k
{
64
1.30k
    fprintf(logfile, "HTPCallbackResponseHasTrailer\n");
65
1.30k
    return 0;
66
1.30k
}
67
68
static int HTPCallbackRequestBodyData(htp_tx_data_t *tx_data)
69
103k
{
70
103k
    fprintf(logfile, "HTPCallbackRequestBodyData %"PRIuMAX"\n", (uintmax_t)tx_data->len);
71
103k
    if (tx_data->len > 0 && tx_data->data != NULL) {
72
103k
        fprintf(logfile, "HTPCallbackRequestBodyData %x %x\n", tx_data->data[0], tx_data->data[(uintmax_t)tx_data->len-1]);
73
103k
    }
74
103k
    return 0;
75
103k
}
76
77
static int HTPCallbackResponseBodyData(htp_tx_data_t *tx_data)
78
1.93M
{
79
1.93M
    fprintf(logfile, "HTPCallbackResponseBodyData %"PRIuMAX"\n", (uintmax_t)tx_data->len);
80
1.93M
    if (tx_data->len > 0 && tx_data->data != NULL) {
81
1.92M
        fprintf(logfile, "HTPCallbackResponseBodyData %x %x\n", tx_data->data[0], tx_data->data[(uintmax_t)tx_data->len-1]);
82
1.92M
    }
83
1.93M
    return 0;
84
1.93M
}
85
86
static int HTPCallbackRequestStart(htp_tx_t *tx)
87
64.9k
{
88
64.9k
    fprintf(logfile, "HTPCallbackRequestStart\n");
89
64.9k
    return 0;
90
64.9k
}
91
92
static int HTPCallbackRequest(htp_tx_t *tx)
93
91.9k
{
94
91.9k
    fprintf(logfile, "HTPCallbackRequest\n");
95
91.9k
    return 0;
96
91.9k
}
97
98
static int HTPCallbackResponseStart(htp_tx_t *tx)
99
35.1k
{
100
35.1k
    fprintf(logfile, "HTPCallbackResponseStart\n");
101
35.1k
    return 0;
102
35.1k
}
103
104
static int HTPCallbackRequestLine(htp_tx_t *tx)
105
64.4k
{
106
64.4k
    fprintf(logfile, "HTPCallbackRequestLine\n");
107
64.4k
    return 0;
108
64.4k
}
109
110
/**
111
 * Invoked every time LibHTP wants to log. 
112
 *
113
 * @param[in] log
114
 */
115
3.27M
static int HTPCallbackLog(htp_log_t *log) {
116
3.27M
    fprintf(logfile, "HTPCallbackLog [%d][code %d][file %s][line %d] %s\n",
117
3.27M
        log->level, log->code, log->file, log->line, log->msg);
118
3.27M
    return 0;
119
3.27M
}
120
121
0
void fuzz_openFile(const char * name) {
122
0
    if (logfile != NULL) {
123
0
        fclose(logfile);
124
0
    }
125
0
    logfile = fopen(name, "w");
126
0
}
127
128
9.92k
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
129
9.92k
    htp_cfg_t *cfg;
130
9.92k
    htp_connp_t * connp;
131
9.92k
    int rc;
132
9.92k
    test_t test;
133
134
    //initialize output file
135
9.92k
    if (logfile == NULL) {
136
1
        logfile = fopen("/dev/null", "w");
137
1
        if (logfile == NULL) {
138
0
            abort();
139
0
        }
140
1
    }
141
142
    // Create LibHTP configuration
143
9.92k
    cfg = htp_config_create();
144
9.92k
    if (htp_config_set_server_personality(cfg, HTP_SERVER_IDS) != HTP_OK) {
145
0
        htp_config_destroy(cfg);
146
0
        return 0;
147
0
    }
148
9.92k
    htp_config_register_log(cfg, HTPCallbackLog);
149
9.92k
    htp_config_register_request_header_data(cfg, HTPCallbackRequestHeaderData);
150
9.92k
    htp_config_register_request_trailer_data(cfg, HTPCallbackRequestHeaderData);
151
9.92k
    htp_config_register_response_header_data(cfg, HTPCallbackResponseHeaderData);
152
9.92k
    htp_config_register_response_trailer_data(cfg, HTPCallbackResponseHeaderData);
153
9.92k
    htp_config_register_request_trailer(cfg, HTPCallbackRequestHasTrailer);
154
9.92k
    htp_config_register_response_trailer(cfg, HTPCallbackResponseHasTrailer);
155
9.92k
    htp_config_register_request_body_data(cfg, HTPCallbackRequestBodyData);
156
9.92k
    htp_config_register_response_body_data(cfg, HTPCallbackResponseBodyData);
157
9.92k
    htp_config_register_request_start(cfg, HTPCallbackRequestStart);
158
9.92k
    htp_config_register_request_complete(cfg, HTPCallbackRequest);
159
9.92k
    htp_config_register_response_start(cfg, HTPCallbackResponseStart);
160
9.92k
    htp_config_register_response_complete(cfg, HTPCallbackResponse);
161
9.92k
    htp_config_register_request_line(cfg, HTPCallbackRequestLine);
162
9.92k
    htp_config_set_max_tx(cfg, 512);
163
164
9.92k
    connp = htp_connp_create(cfg);
165
9.92k
    htp_connp_set_user_data(connp, (void *) 0x02);
166
9.92k
    htp_connp_open(connp, (const char *) "192.168.2.3", 12345, (const char *) "192.168.2.2", 80, NULL);
167
168
9.92k
    test.buf = (char *)Data;
169
9.92k
    test.len = Size;
170
9.92k
    test.pos = 0;
171
9.92k
    test.chunk = NULL;
172
173
    // Find all chunks and feed them to the parser
174
9.92k
    int in_data_other = 0;
175
9.92k
    char *in_data = NULL;
176
9.92k
    size_t in_data_len = 0;
177
9.92k
    size_t in_data_offset = 0;
178
9.92k
    int out_data_other = 0;
179
9.92k
    char *out_data = NULL;
180
9.92k
    size_t out_data_len = 0;
181
9.92k
    size_t out_data_offset = 0;
182
183
226k
    for (;;) {
184
226k
        if (test_next_chunk(&test) <= 0) {
185
9.84k
            break;
186
9.84k
        }
187
216k
        if (test.chunk_len == 0) {
188
1.48k
            continue;
189
1.48k
        }
190
214k
        if (test.chunk_direction == CLIENT) {
191
149k
            if (in_data_other) {
192
14
                break;
193
14
            }
194
149k
            rc = htp_connp_req_data(connp, NULL, test.chunk, test.chunk_len);
195
149k
            if (rc == HTP_STREAM_ERROR) {
196
32
                break;
197
32
            }
198
149k
            if (rc == HTP_STREAM_DATA_OTHER) {
199
                // Parser needs to see the outbound stream in order to continue
200
                // parsing the inbound stream.
201
932
                in_data_other = 1;
202
932
                in_data = test.chunk;
203
932
                in_data_len = test.chunk_len;
204
932
                in_data_offset = htp_connp_req_data_consumed(connp);
205
932
            }
206
149k
        } else {
207
65.2k
            if (out_data_other) {
208
1.04k
                if (out_data == NULL) {
209
446
                    rc = htp_connp_res_data(connp, NULL, NULL, out_data_len - out_data_offset);
210
597
                } else {
211
597
                    rc = htp_connp_res_data(connp, NULL, out_data + out_data_offset, out_data_len - out_data_offset);
212
597
                }
213
1.04k
                if (rc == HTP_STREAM_ERROR) {
214
1
                    break;
215
1
                }
216
1.04k
                out_data_other = 0;
217
1.04k
            }
218
65.2k
            rc = htp_connp_res_data(connp, NULL, test.chunk, test.chunk_len);
219
65.2k
            if (rc == HTP_STREAM_ERROR) {
220
32
                break;
221
32
            }
222
65.2k
            if (rc == HTP_STREAM_DATA_OTHER) {
223
                // Parser needs to see the outbound stream in order to continue
224
                // parsing the inbound stream.
225
1.08k
                out_data_other = 1;
226
1.08k
                out_data = test.chunk;
227
1.08k
                out_data_len = test.chunk_len;
228
1.08k
                out_data_offset = htp_connp_res_data_consumed(connp);
229
1.08k
            }
230
65.2k
            if (in_data_other) {
231
898
                if (in_data == NULL) {
232
0
                    rc = htp_connp_req_data(connp, NULL, NULL, in_data_len - in_data_offset);
233
898
                } else {
234
898
                    rc = htp_connp_req_data(connp, NULL, in_data + in_data_offset, in_data_len - in_data_offset);
235
898
                }
236
898
                if (rc == HTP_STREAM_ERROR) {
237
1
                    break;
238
1
                }
239
897
                in_data_other = 0;
240
897
            }
241
65.2k
        }
242
214k
    }
243
9.92k
    if (out_data_other) {
244
40
        if (out_data == NULL) {
245
9
            (void) htp_connp_res_data(connp, NULL, NULL, out_data_len - out_data_offset);
246
31
        } else {
247
31
            (void) htp_connp_res_data(connp, NULL, out_data + out_data_offset, out_data_len - out_data_offset);
248
31
        }
249
40
    }
250
251
9.92k
    htp_connp_close(connp, NULL);
252
9.92k
    htp_connp_destroy_all(connp);
253
    // Destroy LibHTP configuration    
254
9.92k
    htp_config_destroy(cfg);
255
256
9.92k
    return 0;
257
9.92k
}
258