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"
12 #include "util-unittest-helper.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 
20 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
21 int LLVMFuzzerInitialize(int *argc, char ***argv);
22 
24 
25 extern 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 
37 const uint8_t separator[] = {0x01, 0xD5, 0xCA, 0x7A};
40 char *target_suffix = NULL;
41 SC_ATOMIC_EXTERN(unsigned int, engine_stage);
42 
43 int 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 
53 int 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) {
84  AppProto applayer = StringToAppProto(target_suffix + 1);
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 
123  FLOWLOCK_WRLOCK(f);
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);
198  (void)AppLayerParserParse(
199  NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, (uint32_t)alsize);
200  free(isolatedBuffer);
201  }
202 
203 bail:
204  FLOWLOCK_UNLOCK(f);
205  FlowFree(f);
206 
207  return 0;
208 }
util-byte.h
SCConfYamlLoadString
int SCConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
Definition: conf-yaml-loader.c:523
SCAppLayerParserStateIssetFlag
uint16_t SCAppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1829
surifuzz
SCInstance surifuzz
Definition: fuzz_applayerparserparse.c:38
flow-util.h
SC_ATOMIC_SET
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:386
AppLayerParserTransactionsCleanup
void AppLayerParserTransactionsCleanup(Flow *f, const uint8_t pkt_dir)
remove obsolete (inspected and logged) transactions
Definition: app-layer-parser.c:903
FLOW_SGH_TOCLIENT
#define FLOW_SGH_TOCLIENT
Definition: flow.h:75
Flow_::proto
uint8_t proto
Definition: flow.h:378
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:86
LLVMFuzzerInitialize
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition: fuzz_applayerparserparse.c:43
configNoChecksum
const char * configNoChecksum
Definition: confyaml.c:1
Flow_
Flow data structure.
Definition: flow.h:356
Flow_::protomap
uint8_t protomap
Definition: flow.h:445
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:40
rust.h
GlobalsInitPreConfig
void GlobalsInitPreConfig(void)
Definition: suricata.c:377
Flow_::dp
Port dp
Definition: flow.h:372
HEADER_LEN
#define HEADER_LEN
Definition: fuzz_applayerparserparse.c:18
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:53
Flow_::protoctx
void * protoctx
Definition: flow.h:441
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:100
util-unittest-helper.h
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:273
SCRunmodeSet
void SCRunmodeSet(SCRunMode run_mode)
Set the current run mode.
Definition: suricata.c:284
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:478
Flow_::dst
FlowAddress dst
Definition: flow.h:359
app-layer-detect-proto.h
separator
const uint8_t separator[]
Definition: fuzz_applayerparserparse.c:37
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:29
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:23
StringToAppProto
AppProto StringToAppProto(const char *proto_name)
Maps a string to its ALPROTO_* equivalent.
Definition: app-layer-protos.c:60
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:270
PostConfLoadedSetup
int PostConfLoadedSetup(SCInstance *suri)
Definition: suricata.c:2711
app-layer-parser.h
FlowGetProtoMapping
uint8_t FlowGetProtoMapping(uint8_t proto)
Function to map the protocol to the defined FLOW_PROTO_* enumeration.
Definition: flow-util.c:99
conf-yaml-loader.h
APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TC
Definition: app-layer-parser.h:54
setenv
void setenv(const char *name, const char *value, int overwrite)
Flow_::src
FlowAddress src
Definition: flow.h:359
target_suffix
char * target_suffix
Definition: fuzz_applayerparserparse.c:40
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:297
util-conf.h
flags
uint8_t flags
Definition: decode-gre.h:0
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1291
suricata-common.h
FlowFree
void FlowFree(Flow *f)
cleanup & free the memory of a flow
Definition: flow-util.c:84
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
SURICATA_RUNTIME
@ SURICATA_RUNTIME
Definition: suricata.h:101
ConfigSetLogDirectory
TmEcode ConfigSetLogDirectory(const char *name)
Definition: util-conf.c:33
FLOW_SGH_TOSERVER
#define FLOW_SGH_TOSERVER
Definition: flow.h:73
Flow_::flags
uint32_t flags
Definition: flow.h:421
ALPROTO_HTTP
@ ALPROTO_HTTP
Definition: app-layer-protos.h:76
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
suricata.h
SCInstance_
Definition: suricata.h:133
SC_ATOMIC_EXTERN
SC_ATOMIC_EXTERN(unsigned int, engine_stage)
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:60
InitGlobal
int InitGlobal(void)
Global initialization common to all runmodes.
Definition: suricata.c:2958
FlowChangeProto
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition: flow.c:196
Flow_::sp
Port sp
Definition: flow.h:361
TcpSession_
Definition: stream-tcp-private.h:283
FlowAlloc
Flow * FlowAlloc(void)
allocate a flow
Definition: flow-util.c:56
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
RUNMODE_PCAP_FILE
@ RUNMODE_PCAP_FILE
Definition: runmodes.h:30
LLVMFuzzerTestOneInput
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition: fuzz_applayerparserparse.c:53
forceLayer
AppProto forceLayer
Definition: fuzz_applayerparserparse.c:39