decode: limits the number of decoded layers

so as to avoid overrecursion leading to stack exhaustion

(cherry picked from commit 7500c29300)
pull/5962/head
Philippe Antoine 5 years ago committed by Victor Julien
parent 0495be247c
commit 82a8124f58

@ -146,5 +146,7 @@ alert pkthdr any any -> any any (msg:"SURICATA DCE packet too small"; decode-eve
# Cisco HDLC
alert pkthdr any any -> any any (msg:"SURICATA CHDLC packet too small"; decode-event:chdlc.pkt_too_small; classtype:protocol-command-decode; sid:2200115; rev:1;)
# next sid is 2200116
alert pkthdr any any -> any any (msg:"SURICATA packet with too many layers"; decode-event:too_many_layers; classtype:protocol-command-decode; sid:2200116; rev:1;)
# next sid is 2200117

@ -51,6 +51,9 @@ int DecodeCHDLC(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
if (unlikely(len > CHDLC_HEADER_LEN + USHRT_MAX)) {
return TM_ECODE_FAILED;
}
if (!PacketIncreaseCheckLayers(p)) {
return TM_ECODE_FAILED;
}
CHDLCHdr *hdr = (CHDLCHdr *)pkt;
if (unlikely(hdr == NULL))

@ -80,6 +80,9 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t
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;

@ -48,6 +48,9 @@ int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
return TM_ECODE_FAILED;
}
if (!PacketIncreaseCheckLayers(p)) {
return TM_ECODE_FAILED;
}
p->ethh = (EthernetHdr *)pkt;
if (unlikely(p->ethh == NULL))
return TM_ECODE_FAILED;

@ -535,6 +535,11 @@ const struct DecodeEvents_ DEvents[] = {
CHDLC_PKT_TOO_SMALL,
},
{
"decoder.too_many_layers",
GENERIC_TOO_MANY_LAYERS,
},
/* STREAM EVENTS */
{
"stream.3whs_ack_in_wrong_dir",

@ -200,8 +200,11 @@ enum {
/* Cisco HDLC events. */
CHDLC_PKT_TOO_SMALL,
/* generic events */
GENERIC_TOO_MANY_LAYERS,
/* END OF DECODE EVENTS ON SINGLE PACKET */
DECODE_EVENT_PACKET_MAX = CHDLC_PKT_TOO_SMALL,
DECODE_EVENT_PACKET_MAX = GENERIC_TOO_MANY_LAYERS,
/* STREAM EVENTS */
STREAM_3WHS_ACK_IN_WRONG_DIR,

@ -194,6 +194,9 @@ int DecodeGeneve(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t
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);

@ -54,6 +54,9 @@ int DecodeGRE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *p
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)

@ -521,6 +521,9 @@ int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
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");

@ -581,6 +581,9 @@ int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *
{
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)) {

@ -53,6 +53,9 @@ int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
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);

@ -49,6 +49,9 @@ int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
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))

@ -45,6 +45,9 @@ int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
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))

@ -62,6 +62,15 @@ int DecodeTEMPLATE(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
//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;

@ -70,6 +70,9 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
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;

@ -136,6 +136,9 @@ int DecodeVXLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,
if (len < (VXLAN_HEADER_LEN + 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)

@ -72,9 +72,13 @@ uint32_t default_packet_size = 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, enum DecodeTunnelProto proto)
static int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t,
enum DecodeTunnelProto) WARN_UNUSED;
static int DecodeTunnel(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt,
uint32_t len, enum DecodeTunnelProto proto)
{
switch (proto) {
case DECODE_TUNNEL_PPP:
@ -760,6 +764,14 @@ void DecodeGlobalConfig(void)
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;
}
}
}
/**

@ -607,6 +607,11 @@ typedef struct Packet_
*/
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
@ -822,6 +827,7 @@ void CaptureStatsSetup(ThreadVars *tv, CaptureStats *s);
PACKET_RESET_CHECKSUMS((p)); \
PACKET_PROFILING_RESET((p)); \
p->tenant_id = 0; \
p->nb_decoded_layers = 0; \
} while (0)
#define PACKET_RECYCLE(p) do { \
@ -942,7 +948,6 @@ int DecodeSll(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint3
int DecodePPP(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodePPPOESession(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodePPPOEDiscovery(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeTunnel(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t, enum DecodeTunnelProto) WARN_UNUSED;
int DecodeNull(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeRaw(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint32_t);
int DecodeIPV4(ThreadVars *, DecodeThreadVars *, Packet *, const uint8_t *, uint16_t);
@ -1149,6 +1154,19 @@ void DecodeUnregisterCounters(void);
#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,

@ -1361,6 +1361,9 @@ decoder:
enabled: true
ports: $GENEVE_PORTS # syntax: '[6081, 1234]' or '6081'.
# maximum number of decoder layers for a packet
# max-layers: 16
##
## Performance tuning and profiling
##

Loading…
Cancel
Save