suricata
fuzz_applayerparserparse.c
Go to the documentation of this file.
1/**
2 * @file
3 * @author Philippe Antoine <contact@catenacyber.fr>
4 * fuzz target for AppLayerParserParse
5 */
6
7#include "suricata-common.h"
8#include "suricata.h"
10#include "flow-util.h"
11#include "app-layer-parser.h"
13#include "util-byte.h"
14#include "conf-yaml-loader.h"
15#include "util-conf.h"
16#include "rust.h"
17
18#define HEADER_LEN 6
19
20int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
21int LLVMFuzzerInitialize(int *argc, char ***argv);
22
24
25extern const char *configNoChecksum;
26
27/* input buffer is structured this way :
28 * 6 bytes header,
29 * then sequence of buffers separated by magic bytes 01 D5 CA 7A */
30
31/* The 6 bytes header is
32 * alproto
33 * proto
34 * source port (uint16_t)
35 * destination port (uint16_t) */
36
37const uint8_t separator[] = {0x01, 0xD5, 0xCA, 0x7A};
40char *target_suffix = NULL;
41SC_ATOMIC_EXTERN(unsigned int, engine_stage);
42
43int LLVMFuzzerInitialize(int *argc, char ***argv)
44{
45 target_suffix = strrchr((*argv)[0], '_');
46 // else
47 if (!target_suffix) {
48 target_suffix = getenv("FUZZ_APPLAYER");
49 }
50 return 0;
51}
52
53int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
54{
55 Flow * f;
56 TcpSession ssn;
57 const uint8_t * albuffer;
58 uint8_t * alnext;
59 size_t alsize;
60 // used to find under and overflows
61 // otherwise overflows do not fail as they read the next packet
62 uint8_t * isolatedBuffer;
63
64 if (alp_tctx == NULL) {
65 //Redirects logs to /dev/null
66 setenv("SC_LOG_OP_IFACE", "file", 0);
67 setenv("SC_LOG_FILE", "/dev/null", 0);
68
69 InitGlobal();
72
73 //redirect logs to /tmp
74 ConfigSetLogDirectory("/tmp/");
75 // disables checksums validation for fuzzing
77 abort();
78 }
79
82 SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME);
83 if (target_suffix != NULL) {
85 if (applayer != ALPROTO_UNKNOWN) {
86 forceLayer = applayer;
87 printf("Forcing %s=%" PRIu16 "\n", AppProtoToString(forceLayer), forceLayer);
88 }
89 }
90 // http is the output name, but we want to fuzz HTTP1
91 if (forceLayer == ALPROTO_HTTP) {
93 }
94 }
95
96 if (size < HEADER_LEN) {
97 return 0;
98 }
99
100 if (data[0] >= g_alproto_max) {
101 return 0;
102 }
103 //no UTHBuildFlow to have storage
104 f = FlowAlloc();
105 if (f == NULL) {
106 return 0;
107 }
109 f->src.addr_data32[0] = 0x01020304;
110 f->dst.addr_data32[0] = 0x05060708;
111 f->sp = (uint16_t)((data[2] << 8) | data[3]);
112 f->dp = (uint16_t)((data[4] << 8) | data[5]);
113 f->proto = data[1];
114 memset(&ssn, 0, sizeof(TcpSession));
115 f->protoctx = &ssn;
117 if (forceLayer > 0) {
118 f->alproto = forceLayer;
119 } else {
120 f->alproto = data[0];
121 }
122
124 /*
125 * We want to fuzz multiple calls to AppLayerParserParse
126 * because some parts of the code are only reached after
127 * multiple packets (in SMTP for example).
128 * So we treat our input as a list of buffers with magic separator.
129 */
130 albuffer = data + HEADER_LEN;
131 alsize = size - HEADER_LEN;
132 uint8_t flags = STREAM_START;
133 int flip = 0;
134 alnext = memmem(albuffer, alsize, separator, 4);
135 while (alnext) {
136 if (flip) {
137 flags |= STREAM_TOCLIENT;
138 flags &= ~(STREAM_TOSERVER);
139 flip = 0;
140 } else {
141 flags |= STREAM_TOSERVER;
142 flags &= ~(STREAM_TOCLIENT);
143 flip = 1;
144 }
145
146 if (alnext != albuffer) {
147 // only if we have some data
148 isolatedBuffer = malloc(alnext - albuffer);
149 if (isolatedBuffer == NULL) {
150 goto bail;
151 }
152 memcpy(isolatedBuffer, albuffer, alnext - albuffer);
153 (void)AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer,
154 (uint32_t)(alnext - albuffer));
155 free(isolatedBuffer);
156 if (FlowChangeProto(f)) {
157 // exits if a protocol change is requested
158 alsize = 0;
159 break;
160 }
161 flags &= ~(STREAM_START);
162 if (f->alparser &&
163 (((flags & STREAM_TOSERVER) != 0 && SCAppLayerParserStateIssetFlag(f->alparser,
165 ((flags & STREAM_TOCLIENT) != 0 &&
168 //no final chunk
169 alsize = 0;
170 break;
171 }
172
173 AppLayerParserTransactionsCleanup(f, flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
174 }
175 alsize -= alnext - albuffer + 4;
176 albuffer = alnext + 4;
177 if (alsize == 0) {
178 break;
179 }
180 alnext = memmem(albuffer, alsize, separator, 4);
181 }
182 if (alsize > 0 ) {
183 if (flip) {
184 flags |= STREAM_TOCLIENT;
185 flags &= ~(STREAM_TOSERVER);
186 flip = 0;
187 } else {
188 flags |= STREAM_TOSERVER;
189 flags &= ~(STREAM_TOCLIENT);
190 flip = 1;
191 }
192 flags |= STREAM_EOF;
193 isolatedBuffer = malloc(alsize);
194 if (isolatedBuffer == NULL) {
195 goto bail;
196 }
197 memcpy(isolatedBuffer, albuffer, alsize);
199 NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, (uint32_t)alsize);
200 free(isolatedBuffer);
201 }
202
203bail:
205 FlowFree(f);
206
207 return 0;
208}
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir)
remove obsolete (inspected and logged) transactions
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
#define APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TS
AppProto g_alproto_max
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
AppProto StringToAppProto(const char *proto_name)
Maps a string to its ALPROTO_* equivalent.
uint16_t AppProto
@ ALPROTO_HTTP
@ ALPROTO_UNKNOWN
@ ALPROTO_HTTP1
int SCConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
uint8_t flags
Definition decode-gre.h:0
Flow * FlowAlloc(void)
allocate a flow
Definition flow-util.c:56
uint8_t FlowGetProtoMapping(uint8_t proto)
Function to map the protocol to the defined FLOW_PROTO_* enumeration.
Definition flow-util.c:99
void FlowFree(Flow *f)
cleanup & free the memory of a flow
Definition flow-util.c:84
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition flow.c:196
#define FLOW_SGH_TOCLIENT
Definition flow.h:75
#define FLOW_SGH_TOSERVER
Definition flow.h:73
#define FLOW_IPV4
Definition flow.h:100
#define FLOWLOCK_UNLOCK(fb)
Definition flow.h:273
#define FLOWLOCK_WRLOCK(fb)
Definition flow.h:270
AppProto forceLayer
char * target_suffix
const uint8_t separator[]
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
int LLVMFuzzerInitialize(int *argc, char ***argv)
AppLayerParserThreadCtx * alp_tctx
const char * configNoChecksum
Definition confyaml.c:1
#define HEADER_LEN
SCInstance surifuzz
@ RUNMODE_PCAP_FILE
Definition runmodes.h:30
Flow data structure.
Definition flow.h:356
Port dp
Definition flow.h:372
uint8_t proto
Definition flow.h:378
uint32_t flags
Definition flow.h:421
AppProto alproto
application level protocol
Definition flow.h:450
void * protoctx
Definition flow.h:441
AppLayerParserState * alparser
Definition flow.h:478
uint8_t protomap
Definition flow.h:445
FlowAddress src
Definition flow.h:359
Port sp
Definition flow.h:361
FlowAddress dst
Definition flow.h:359
int InitGlobal(void)
Global initialization common to all runmodes.
Definition suricata.c:2965
void SCRunmodeSet(SCRunMode run_mode)
Set the current run mode.
Definition suricata.c:284
void GlobalsInitPreConfig(void)
Definition suricata.c:382
int PostConfLoadedSetup(SCInstance *suri)
Definition suricata.c:2716
@ SURICATA_RUNTIME
Definition suricata.h:101
#define SC_ATOMIC_EXTERN(type, name)
wrapper for referencing an atomic variable declared on another file.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
TmEcode ConfigSetLogDirectory(const char *name)
Definition util-conf.c:33
void setenv(const char *name, const char *value, int overwrite)