dnp3: set a bound on the number of points per message

16384 is used as the max, but a configuration parameter has been
provided. The reason for setting an upper bound is that bit flags can
create a memory amplification as we parse them into individual data
structures.

Ticket: #8181
(cherry picked from commit 3a32bb5743)
pull/14599/head
Jason Ish 4 months ago committed by Victor Julien
parent 377c8fded8
commit c03a8db521

@ -40,10 +40,11 @@ Upgrading to 8.0.3
Other Changes
~~~~~~~~~~~~~
- ``dnp3`` has reduced the default maximum number of outstanding
transactions from 500 down to 32. A ``max-tx`` parameter has been
added to the ``dnp3`` parser for users that need a larger number of
in-flight transactions.
- ``dnp3`` has reduced the maximum number of open transactions from
500 down to 32, and the maximum number of points per message from
unbounded to 16384. Configuration options, ``max-tx`` and
``max-points`` have been added for users who may need to change
these defaults.
Upgrading to 8.0.2
------------------

@ -24,3 +24,9 @@ alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad transport CRC"; \
# Unknown object.
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Unknown object"; \
app-layer-event:dnp3.unknown_object; classtype:protocol-command-decode; sid:2270004; rev:2;)
# Too many points in a message.
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Too many points in message"; \
app-layer-event:dnp3.too_many_points; \
threshold:type backoff, track by_flow, count 1, multiplier 10; \
classtype:protocol-command-decode; sid:2270005; rev:1;)

@ -91,15 +91,19 @@ enum {
* attacks. */
static uint64_t dnp3_max_tx = 32;
/* The maximum number of points allowed per message (configurable). */
static uint64_t max_points = 16384;
/* Decoder event map. */
SCEnumCharMap dnp3_decoder_event_table[] = {
{"FLOODED", DNP3_DECODER_EVENT_FLOODED},
{"LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL},
{"BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC},
{"BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC},
{"MALFORMED", DNP3_DECODER_EVENT_MALFORMED},
{"UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT},
{NULL, -1},
{ "FLOODED", DNP3_DECODER_EVENT_FLOODED },
{ "LEN_TOO_SMALL", DNP3_DECODER_EVENT_LEN_TOO_SMALL },
{ "BAD_LINK_CRC", DNP3_DECODER_EVENT_BAD_LINK_CRC },
{ "BAD_TRANSPORT_CRC", DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC },
{ "MALFORMED", DNP3_DECODER_EVENT_MALFORMED },
{ "UNKNOWN_OBJECT", DNP3_DECODER_EVENT_UNKNOWN_OBJECT },
{ "TOO_MANY_POINTS", DNP3_DECODER_EVENT_TOO_MANY_POINTS },
{ NULL, -1 },
};
/* Calculate the next transport sequence number. */
@ -698,6 +702,7 @@ static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf,
uint32_t len, DNP3ObjectList *objects)
{
int retval = 0;
uint64_t point_count = 0;
if (buf == NULL || len == 0) {
return 1;
@ -828,6 +833,13 @@ static int DNP3DecodeApplicationObjects(DNP3Transaction *tx, const uint8_t *buf,
goto next;
}
/* Check if we've exceeded the maximum number of points per message. */
point_count += object->count;
if (point_count > max_points) {
DNP3SetEventTx(tx, DNP3_DECODER_EVENT_TOO_MANY_POINTS);
goto done;
}
int event = DNP3DecodeObject(header->group, header->variation, &buf,
&len, object->prefix_code, object->start, object->count,
object->points);
@ -1596,6 +1608,13 @@ void RegisterDNP3Parsers(void)
if (SCConfGetInt("app-layer.protocols.dnp3.max-tx", &value)) {
dnp3_max_tx = (uint64_t)value;
}
/* Parse max-points configuration. */
if (SCConfGetInt("app-layer.protocols.dnp3.max-points", &value)) {
if (value > 0) {
max_points = (uint64_t)value;
}
}
} else {
SCLogConfig("Parser disabled for protocol %s. "
"Protocol detection still on.", proto_name);

@ -109,6 +109,7 @@ enum {
DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC,
DNP3_DECODER_EVENT_MALFORMED,
DNP3_DECODER_EVENT_UNKNOWN_OBJECT,
DNP3_DECODER_EVENT_TOO_MANY_POINTS,
};
/**

@ -1232,6 +1232,7 @@ app-layer:
detection-ports:
dp: 20000
#max-tx: 32
#max-points: 16384
# SCADA EtherNet/IP and CIP protocol support
enip:

Loading…
Cancel
Save