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 
17 #define HEADER_LEN 6
18 
19 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
20 int LLVMFuzzerInitialize(int *argc, char ***argv);
21 
23 
24 #include "confyaml.c"
25 
26 /* input buffer is structured this way :
27  * 6 bytes header,
28  * then sequence of buffers separated by magic bytes 01 D5 CA 7A */
29 
30 /* The 6 bytes header is
31  * alproto
32  * proto
33  * source port (uint16_t)
34  * destination port (uint16_t) */
35 
36 const uint8_t separator[] = {0x01, 0xD5, 0xCA, 0x7A};
39 SC_ATOMIC_EXTERN(unsigned int, engine_stage);
40 
41 int LLVMFuzzerInitialize(int *argc, char ***argv)
42 {
43  char *target_suffix = strrchr((*argv)[0], '_');
44  if (target_suffix != NULL) {
45  AppProto applayer = StringToAppProto(target_suffix + 1);
46  if (applayer != ALPROTO_UNKNOWN) {
47  forceLayer = applayer;
48  printf("Forcing %s=%" PRIu16 "\n", AppProtoToString(forceLayer), forceLayer);
49  return 0;
50  }
51  }
52  // else
53  const char *forceLayerStr = getenv("FUZZ_APPLAYER");
54  if (forceLayerStr) {
55  if (ByteExtractStringUint16(&forceLayer, 10, 0, forceLayerStr) < 0) {
56  forceLayer = 0;
57  printf("Invalid numeric value for FUZZ_APPLAYER environment variable");
58  } else {
59  printf("Forcing %s\n", AppProtoToString(forceLayer));
60  }
61  }
62  // http is the output name, but we want to fuzz HTTP1
63  if (forceLayer == ALPROTO_HTTP) {
65  }
66  return 0;
67 }
68 
69 // arbitrary value
70 #define ALPROTO_MAXTX 4096
71 
72 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
73 {
74  Flow * f;
75  TcpSession ssn;
76  const uint8_t * albuffer;
77  uint8_t * alnext;
78  size_t alsize;
79  // used to find under and overflows
80  // otherwise overflows do not fail as they read the next packet
81  uint8_t * isolatedBuffer;
82 
83  if (alp_tctx == NULL) {
84  //Redirects logs to /dev/null
85  setenv("SC_LOG_OP_IFACE", "file", 0);
86  setenv("SC_LOG_FILE", "/dev/null", 0);
87 
88  InitGlobal();
91 
92  //redirect logs to /tmp
93  ConfigSetLogDirectory("/tmp/");
94  // disables checksums validation for fuzzing
96  abort();
97  }
98 
101  SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME);
102  }
103 
104  if (size < HEADER_LEN) {
105  return 0;
106  }
107 
108  if (data[0] >= ALPROTO_MAX) {
109  return 0;
110  }
111  //no UTHBuildFlow to have storage
112  f = FlowAlloc();
113  if (f == NULL) {
114  return 0;
115  }
116  f->flags |= FLOW_IPV4;
117  f->src.addr_data32[0] = 0x01020304;
118  f->dst.addr_data32[0] = 0x05060708;
119  f->sp = (uint16_t)((data[2] << 8) | data[3]);
120  f->dp = (uint16_t)((data[4] << 8) | data[5]);
121  f->proto = data[1];
122  memset(&ssn, 0, sizeof(TcpSession));
123  f->protoctx = &ssn;
125  if (forceLayer > 0) {
126  f->alproto = forceLayer;
127  } else {
128  f->alproto = data[0];
129  }
130 
131  FLOWLOCK_WRLOCK(f);
132  /*
133  * We want to fuzz multiple calls to AppLayerParserParse
134  * because some parts of the code are only reached after
135  * multiple packets (in SMTP for example).
136  * So we treat our input as a list of buffers with magic separator.
137  */
138  albuffer = data + HEADER_LEN;
139  alsize = size - HEADER_LEN;
140  uint8_t flags = STREAM_START;
141  int flip = 0;
142  alnext = memmem(albuffer, alsize, separator, 4);
143  while (alnext) {
144  if (flip) {
145  flags |= STREAM_TOCLIENT;
146  flags &= ~(STREAM_TOSERVER);
147  flip = 0;
148  } else {
149  flags |= STREAM_TOSERVER;
150  flags &= ~(STREAM_TOCLIENT);
151  flip = 1;
152  }
153 
154  if (alnext != albuffer) {
155  // only if we have some data
156  isolatedBuffer = malloc(alnext - albuffer);
157  if (isolatedBuffer == NULL) {
158  goto bail;
159  }
160  memcpy(isolatedBuffer, albuffer, alnext - albuffer);
161  (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alnext - albuffer);
162  free(isolatedBuffer);
163  if (FlowChangeProto(f)) {
164  // exits if a protocol change is requested
165  alsize = 0;
166  break;
167  }
168  flags &= ~(STREAM_START);
169  if (f->alparser &&
170  (((flags & STREAM_TOSERVER) != 0 &&
172  ((flags & STREAM_TOCLIENT) != 0 &&
174  //no final chunk
175  alsize = 0;
176  break;
177  }
178 
179  AppLayerParserTransactionsCleanup(f, flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
180  }
181  alsize -= alnext - albuffer + 4;
182  albuffer = alnext + 4;
183  if (alsize == 0) {
184  break;
185  }
186  alnext = memmem(albuffer, alsize, separator, 4);
187  }
188  if (alsize > 0 ) {
189  if (flip) {
190  flags |= STREAM_TOCLIENT;
191  flags &= ~(STREAM_TOSERVER);
192  flip = 0;
193  } else {
194  flags |= STREAM_TOSERVER;
195  flags &= ~(STREAM_TOCLIENT);
196  flip = 1;
197  }
198  flags |= STREAM_EOF;
199  isolatedBuffer = malloc(alsize);
200  if (isolatedBuffer == NULL) {
201  goto bail;
202  }
203  memcpy(isolatedBuffer, albuffer, alsize);
204  (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alsize);
205  free(isolatedBuffer);
206  }
207 
208 bail:
209  FLOWLOCK_UNLOCK(f);
210  FlowFree(f);
211 
212  return 0;
213 }
util-byte.h
surifuzz
SCInstance surifuzz
Definition: fuzz_applayerparserparse.c:37
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:908
ByteExtractStringUint16
int ByteExtractStringUint16(uint16_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:262
Flow_::proto
uint8_t proto
Definition: flow.h:373
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:81
LLVMFuzzerInitialize
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition: fuzz_applayerparserparse.c:41
Flow_
Flow data structure.
Definition: flow.h:351
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:75
GlobalsInitPreConfig
void GlobalsInitPreConfig(void)
Definition: suricata.c:359
Flow_::dp
Port dp
Definition: flow.h:367
SURICATA_RUNTIME
@ SURICATA_RUNTIME
Definition: suricata.h:96
HEADER_LEN
#define HEADER_LEN
Definition: fuzz_applayerparserparse.c:17
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:39
ALPROTO_MAX
@ ALPROTO_MAX
Definition: app-layer-protos.h:76
Flow_::protoctx
void * protoctx
Definition: flow.h:441
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:97
util-unittest-helper.h
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:268
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:475
Flow_::dst
FlowAddress dst
Definition: flow.h:354
app-layer-detect-proto.h
separator
const uint8_t separator[]
Definition: fuzz_applayerparserparse.c:36
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:22
StringToAppProto
AppProto StringToAppProto(const char *proto_name)
Maps a string to its ALPROTO_* equivalent.
Definition: app-layer-protos.c:95
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:265
ConfYamlLoadString
int ConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
Definition: conf-yaml-loader.c:522
PostConfLoadedSetup
int PostConfLoadedSetup(SCInstance *suri)
Definition: suricata.c:2638
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:97
conf-yaml-loader.h
confyaml.c
APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TC
Definition: app-layer-parser.h:40
setenv
void setenv(const char *name, const char *value, int overwrite)
Flow_::src
FlowAddress src
Definition: flow.h:354
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:291
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:1292
suricata-common.h
FlowFree
void FlowFree(Flow *f)
cleanup & free the memory of a flow
Definition: flow-util.c:82
configNoChecksum
const char configNoChecksum[]
Definition: confyaml.c:1
run_mode
int run_mode
Definition: suricata.c:175
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:30
ConfigSetLogDirectory
TmEcode ConfigSetLogDirectory(const char *name)
Definition: util-conf.c:33
Flow_::flags
uint32_t flags
Definition: flow.h:421
ALPROTO_HTTP
@ ALPROTO_HTTP
Definition: app-layer-protos.h:67
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
suricata.h
SCInstance_
Definition: suricata.h:123
SC_ATOMIC_EXTERN
SC_ATOMIC_EXTERN(unsigned int, engine_stage)
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:65
InitGlobal
int InitGlobal(void)
Global initialization common to all runmodes.
Definition: suricata.c:2873
FlowChangeProto
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition: flow.c:221
Flow_::sp
Port sp
Definition: flow.h:356
TcpSession_
Definition: stream-tcp-private.h:283
FlowAlloc
Flow * FlowAlloc(void)
allocate a flow
Definition: flow-util.c:54
AppLayerParserStateIssetFlag
uint16_t AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1794
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
LLVMFuzzerTestOneInput
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition: fuzz_applayerparserparse.c:72
RUNMODE_PCAP_FILE
@ RUNMODE_PCAP_FILE
Definition: runmodes.h:30
forceLayer
AppProto forceLayer
Definition: fuzz_applayerparserparse.c:38