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 extern const char *configNoChecksum;
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 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
70 {
71  Flow * f;
72  TcpSession ssn;
73  const uint8_t * albuffer;
74  uint8_t * alnext;
75  size_t alsize;
76  // used to find under and overflows
77  // otherwise overflows do not fail as they read the next packet
78  uint8_t * isolatedBuffer;
79 
80  if (alp_tctx == NULL) {
81  //Redirects logs to /dev/null
82  setenv("SC_LOG_OP_IFACE", "file", 0);
83  setenv("SC_LOG_FILE", "/dev/null", 0);
84 
85  InitGlobal();
88 
89  //redirect logs to /tmp
90  ConfigSetLogDirectory("/tmp/");
91  // disables checksums validation for fuzzing
93  abort();
94  }
95 
98  SC_ATOMIC_SET(engine_stage, SURICATA_RUNTIME);
99  }
100 
101  if (size < HEADER_LEN) {
102  return 0;
103  }
104 
105  if (data[0] >= ALPROTO_MAX) {
106  return 0;
107  }
108  //no UTHBuildFlow to have storage
109  f = FlowAlloc();
110  if (f == NULL) {
111  return 0;
112  }
113  f->flags |= FLOW_IPV4;
114  f->src.addr_data32[0] = 0x01020304;
115  f->dst.addr_data32[0] = 0x05060708;
116  f->sp = (uint16_t)((data[2] << 8) | data[3]);
117  f->dp = (uint16_t)((data[4] << 8) | data[5]);
118  f->proto = data[1];
119  memset(&ssn, 0, sizeof(TcpSession));
120  f->protoctx = &ssn;
122  if (forceLayer > 0) {
123  f->alproto = forceLayer;
124  } else {
125  f->alproto = data[0];
126  }
127 
128  FLOWLOCK_WRLOCK(f);
129  /*
130  * We want to fuzz multiple calls to AppLayerParserParse
131  * because some parts of the code are only reached after
132  * multiple packets (in SMTP for example).
133  * So we treat our input as a list of buffers with magic separator.
134  */
135  albuffer = data + HEADER_LEN;
136  alsize = size - HEADER_LEN;
137  uint8_t flags = STREAM_START;
138  int flip = 0;
139  alnext = memmem(albuffer, alsize, separator, 4);
140  while (alnext) {
141  if (flip) {
142  flags |= STREAM_TOCLIENT;
143  flags &= ~(STREAM_TOSERVER);
144  flip = 0;
145  } else {
146  flags |= STREAM_TOSERVER;
147  flags &= ~(STREAM_TOCLIENT);
148  flip = 1;
149  }
150 
151  if (alnext != albuffer) {
152  // only if we have some data
153  isolatedBuffer = malloc(alnext - albuffer);
154  if (isolatedBuffer == NULL) {
155  goto bail;
156  }
157  memcpy(isolatedBuffer, albuffer, alnext - albuffer);
158  (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alnext - albuffer);
159  free(isolatedBuffer);
160  if (FlowChangeProto(f)) {
161  // exits if a protocol change is requested
162  alsize = 0;
163  break;
164  }
165  flags &= ~(STREAM_START);
166  if (f->alparser &&
167  (((flags & STREAM_TOSERVER) != 0 &&
169  ((flags & STREAM_TOCLIENT) != 0 &&
171  //no final chunk
172  alsize = 0;
173  break;
174  }
175 
176  AppLayerParserTransactionsCleanup(f, flags & (STREAM_TOSERVER | STREAM_TOCLIENT));
177  }
178  alsize -= alnext - albuffer + 4;
179  albuffer = alnext + 4;
180  if (alsize == 0) {
181  break;
182  }
183  alnext = memmem(albuffer, alsize, separator, 4);
184  }
185  if (alsize > 0 ) {
186  if (flip) {
187  flags |= STREAM_TOCLIENT;
188  flags &= ~(STREAM_TOSERVER);
189  flip = 0;
190  } else {
191  flags |= STREAM_TOSERVER;
192  flags &= ~(STREAM_TOCLIENT);
193  flip = 1;
194  }
195  flags |= STREAM_EOF;
196  isolatedBuffer = malloc(alsize);
197  if (isolatedBuffer == NULL) {
198  goto bail;
199  }
200  memcpy(isolatedBuffer, albuffer, alsize);
201  (void) AppLayerParserParse(NULL, alp_tctx, f, f->alproto, flags, isolatedBuffer, alsize);
202  free(isolatedBuffer);
203  }
204 
205 bail:
206  FLOWLOCK_UNLOCK(f);
207  FlowFree(f);
208 
209  return 0;
210 }
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:884
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:378
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:81
LLVMFuzzerInitialize
int LLVMFuzzerInitialize(int *argc, char ***argv)
Definition: fuzz_applayerparserparse.c:41
configNoChecksum
const char * configNoChecksum
Definition: confyaml.c:1
Flow_
Flow data structure.
Definition: flow.h:356
Flow_::protomap
uint8_t protomap
Definition: flow.h:450
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:75
SCRunmodeSet
void SCRunmodeSet(int run_mode)
Set the current run mode.
Definition: suricata.c:265
GlobalsInitPreConfig
void GlobalsInitPreConfig(void)
Definition: suricata.c:358
Flow_::dp
Port dp
Definition: flow.h:372
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:446
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:99
util-unittest-helper.h
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:273
Flow_::alparser
AppLayerParserState * alparser
Definition: flow.h:480
Flow_::dst
FlowAddress dst
Definition: flow.h:359
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:270
SURICATA_RUNTIME
@ SURICATA_RUNTIME
Definition: suricata.h:96
ConfYamlLoadString
int ConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
Definition: conf-yaml-loader.c:523
PostConfLoadedSetup
int PostConfLoadedSetup(SCInstance *suri)
Definition: suricata.c:2624
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:98
conf-yaml-loader.h
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:359
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:279
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:1272
suricata-common.h
FlowFree
void FlowFree(Flow *f)
cleanup & free the memory of a flow
Definition: flow-util.c:83
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:426
ALPROTO_HTTP
@ ALPROTO_HTTP
Definition: app-layer-protos.h:70
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:58
InitGlobal
int InitGlobal(void)
Global initialization common to all runmodes.
Definition: suricata.c:2856
FlowChangeProto
int FlowChangeProto(Flow *f)
Check if change proto flag is set for flow.
Definition: flow.c:204
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:55
AppLayerParserStateIssetFlag
uint16_t AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1767
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:455
LLVMFuzzerTestOneInput
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition: fuzz_applayerparserparse.c:69
RUNMODE_PCAP_FILE
@ RUNMODE_PCAP_FILE
Definition: runmodes.h:30
forceLayer
AppProto forceLayer
Definition: fuzz_applayerparserparse.c:38