# Cisco Fabric Path/DCE
alert pkthdr any any -> any any (msg:"SURICATA DCE packet too small"; decode-event:dce.pkt_too_small; classtype:protocol-command-decode; sid:2200110; rev:2;)
-# next sid is 2200114
+alert pkthdr any any -> any any (msg:"SURICATA packet with too many layers"; decode-event:too_many_layers; classtype:protocol-command-decode; sid:2200111; rev:1;)
+# next sid is 2200112
ENGINE_SET_EVENT(p,ERSPAN_HEADER_TOO_SMALL);
return TM_ECODE_FAILED;
}
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
const ErspanHdr *ehdr = (const ErspanHdr *)pkt;
uint16_t version = SCNtohs(ehdr->ver_vlan) >> 12;
return TM_ECODE_FAILED;
}
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
p->ethh = (EthernetHdr *)pkt;
if (unlikely(p->ethh == NULL))
return TM_ECODE_FAILED;
{ "decoder.erspan.too_many_vlan_layers", ERSPAN_TOO_MANY_VLAN_LAYERS, },
/* Cisco Fabric Path/DCE events. */
- { "decoder.dce.pkt_too_small", DCE_PKT_TOO_SMALL, },
+ {
+ "decoder.dce.pkt_too_small",
+ DCE_PKT_TOO_SMALL,
+ },
+
+ {
+ "decoder.too_many_layers",
+ GENERIC_TOO_MANY_LAYERS,
+ },
/* STREAM EVENTS */
{ "stream.3whs_ack_in_wrong_dir", STREAM_3WHS_ACK_IN_WRONG_DIR, },
/* Cisco Fabric Path/DCE events. */
DCE_PKT_TOO_SMALL,
+ /* generic events */
+ GENERIC_TOO_MANY_LAYERS,
+
/* END OF DECODE EVENTS ON SINGLE PACKET */
- DECODE_EVENT_PACKET_MAX = DCE_PKT_TOO_SMALL,
+ DECODE_EVENT_PACKET_MAX = GENERIC_TOO_MANY_LAYERS,
/* STREAM EVENTS */
STREAM_3WHS_ACK_IN_WRONG_DIR,
if (unlikely(len < GENEVE_MIN_HEADER_LEN))
return TM_ECODE_FAILED;
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
/* Specific Geneve header field validation */
geneve_hdr_len = GENEVE_TOTAL_HEADER_LEN(geneve_hdr);
ENGINE_SET_INVALID_EVENT(p, GRE_PKT_TOO_SMALL);
return TM_ECODE_FAILED;
}
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
p->greh = (GREHdr *)pkt;
if(p->greh == NULL)
SCLogDebug("pkt %p len %"PRIu16"", pkt, len);
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
/* do the actual decoding */
if (unlikely(DecodeIPV4Packet (p, pkt, len) < 0)) {
SCLogDebug("decoding IPv4 packet failed");
{
StatsIncr(tv, dtv->counter_ipv6);
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
/* do the actual decoding */
int ret = DecodeIPV6Packet (tv, dtv, p, pkt, len);
if (unlikely(ret < 0)) {
StatsIncr(tv, dtv->counter_mpls);
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
do {
if (len < MPLS_HEADER_LEN) {
ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL);
ENGINE_SET_INVALID_EVENT(p, PPP_PKT_TOO_SMALL);
return TM_ECODE_FAILED;
}
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
p->ppph = (PPPHdr *)pkt;
if (unlikely(p->ppph == NULL))
ENGINE_SET_INVALID_EVENT(p, SLL_PKT_TOO_SMALL);
return TM_ECODE_FAILED;
}
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
SllHdr *sllh = (SllHdr *)pkt;
if (unlikely(sllh == NULL))
//ENGINE_SET_EVENT(p,TEMPLATE_HEADER_TOO_SMALL);
return TM_ECODE_FAILED;
}
+ /* Each packet keeps a count of decoded layers
+ * This function increases it and returns false
+ * if we have too many decoded layers, such as
+ * ethernet/MPLS/ethernet/MPLS... which may
+ * lead to stack overflow by a too deep recursion
+ */
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
/* Now we can access the header */
const TemplateHdr *hdr = (const TemplateHdr *)pkt;
ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL);
return TM_ECODE_FAILED;
}
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
if (p->vlan_idx >= 2) {
ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS);
return TM_ECODE_FAILED;
if (len < (sizeof(VXLANHeader) + sizeof(EthernetHdr)))
return TM_ECODE_FAILED;
+ if (!PacketIncreaseCheckLayers(p)) {
+ return TM_ECODE_FAILED;
+ }
const VXLANHeader *vxlanh = (const VXLANHeader *)pkt;
if ((vxlanh->flags[0] & 0x08) == 0 || vxlanh->res != 0) {
extern bool stats_decoder_events;
extern const char *stats_decoder_events_prefix;
extern bool stats_stream_events;
+uint8_t decoder_max_layers = PKT_DEFAULT_MAX_DECODED_LAYERS;
-int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
- const uint8_t *pkt, uint32_t len, PacketQueue *pq, enum DecodeTunnelProto proto)
+static int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t,
+ PacketQueue *, enum DecodeTunnelProto) WARN_UNUSED;
+
+static int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt,
+ uint32_t len, PacketQueue *pq, enum DecodeTunnelProto proto)
{
switch (proto) {
case DECODE_TUNNEL_PPP:
DecodeGeneveConfig();
DecodeVXLANConfig();
DecodeERSPANConfig();
+ intmax_t value = 0;
+ if (ConfGetInt("decoder.max-layers", &value) == 1) {
+ if (value < 0 || value > UINT8_MAX) {
+ SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid value for decoder.max-layers");
+ } else {
+ decoder_max_layers = value;
+ }
+ }
}
/**
*/
struct PktPool_ *pool;
+ /* count decoded layers of packet : too many layers
+ * cause issues with performance and stability (stack exhaustion)
+ */
+ uint8_t nb_decoded_layers;
+
#ifdef PROFILING
PktProfiling *profile;
#endif
PACKET_RESET_CHECKSUMS((p)); \
PACKET_PROFILING_RESET((p)); \
p->tenant_id = 0; \
+ p->nb_decoded_layers = 0; \
} while (0)
#define PACKET_RECYCLE(p) do { \
int DecodePPP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, PacketQueue *);
int DecodePPPOESession(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, PacketQueue *);
int DecodePPPOEDiscovery(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, PacketQueue *);
-int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, PacketQueue *, enum DecodeTunnelProto) __attribute__ ((warn_unused_result));
int DecodeNull(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, PacketQueue *);
int DecodeRaw(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, PacketQueue *);
int DecodeIPV4(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t, PacketQueue *);
#define PKT_SET_SRC(p, src_val) ((p)->pkt_src = src_val)
+#define PKT_DEFAULT_MAX_DECODED_LAYERS 16
+extern uint8_t decoder_max_layers;
+
+static inline bool PacketIncreaseCheckLayers(Packet *p)
+{
+ p->nb_decoded_layers++;
+ if (p->nb_decoded_layers >= decoder_max_layers) {
+ ENGINE_SET_INVALID_EVENT(p, GENERIC_TOO_MANY_LAYERS);
+ return false;
+ }
+ return true;
+}
+
/** \brief return true if *this* packet needs to trigger a verdict.
*
* If we have the root packet, and we have none outstanding,
enabled: false
ports: $GENEVE_PORTS # syntax: '[6081, 1234]' or '6081'.
+ # maximum number of decoder layers for a packet
+ # max-layers: 16
+
##
## Performance tuning and profiling
##