Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/userguide/rules/payload-keywords.rst
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ When ``relative`` is included, there must be a previous ``content`` or ``pcre``

Note: if ``oper`` is ``/`` and the divisor is 0, there will never be a match on the ``byte_math`` keyword.

Note: if ``oper`` is ``<<`` or ``>>`` and ``rvalue`` is 64 or greater, the result is 0.

The result can be stored in a result variable and referenced by
other rule options later in the rule.

Expand Down
33 changes: 29 additions & 4 deletions rust/src/detect/byte_math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,21 @@ fn parse_bytemath(input: &str) -> IResult<&str, DetectByteMathData, RuleParseErr
)));
}

// Using left/right shift further restricts the value of nbytes. Note that
// validation has already ensured nbytes is in [1..10]
// Using left/right shift further restricts the values of nbytes and rvalue.
// Note that validation has already ensured nbytes is in [1..10]
match byte_math.oper {
ByteMathOperator::LeftShift | ByteMathOperator::RightShift if byte_math.nbytes > 4 => {
return Err(make_error(format!("nbytes must be 1 through 4 (inclusive) when used with \"<<\" or \">>\"; {} is not valid", byte_math.nbytes)));
ByteMathOperator::LeftShift | ByteMathOperator::RightShift => {
if byte_math.nbytes > 4 {
return Err(make_error(format!("nbytes must be 1 through 4 (inclusive) when used with \"<<\" or \">>\"; {} is not valid", byte_math.nbytes)));
}
// A shift of 64 or more always yields 0. Reject the literal form;
// the variable form is only known at match time.
if 0 == (byte_math.flags & DETECT_BYTEMATH_FLAG_RVALUE_VAR) && byte_math.rvalue >= 64 {
return Err(make_error(format!(
"rvalue must be less than 64 when used with \"<<\" or \">>\"; {} is not valid",
byte_math.rvalue
)));
}
}
_ => {}
};
Expand Down Expand Up @@ -618,6 +628,21 @@ mod tests {
);
}

#[test]
// a literal rvalue of 64 or more is rejected with rshift/lshift; a variable
// rvalue is resolved at match time and cannot be checked here
fn test_parser_shift_rvalue() {
assert!(parse_bytemath("bytes 4, offset 3933, oper >>, rvalue 63, result foo").is_ok());
assert!(parse_bytemath("bytes 4, offset 3933, oper <<, rvalue 63, result foo").is_ok());
assert!(parse_bytemath("bytes 4, offset 3933, oper >>, rvalue 64, result foo").is_err());
assert!(parse_bytemath("bytes 4, offset 3933, oper <<, rvalue 64, result foo").is_err());
assert!(parse_bytemath("bytes 4, offset 3933, oper >>, rvalue 100, result foo").is_err());
assert!(parse_bytemath("bytes 4, offset 3933, oper +, rvalue 100, result foo").is_ok());
assert!(
parse_bytemath("bytes 4, offset 3933, oper >>, rvalue myrvalue, result foo").is_ok()
);
}

#[test]
fn test_parser_bitmask_invalid() {
assert!(parse_bytemath(
Expand Down
56 changes: 54 additions & 2 deletions src/detect-bytemath.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2020-2022 Open Information Security Foundation
/* Copyright (C) 2020-2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
Expand Down Expand Up @@ -189,7 +189,11 @@ int DetectByteMathDoMatch(DetectEngineThreadCtx *det_ctx, const DetectByteMathDa
}
break;
case RightShift:
val >>= rvalue;
if (rvalue < 64) {
val >>= rvalue;
} else {
val = 0;
}
break;
}

Expand Down Expand Up @@ -999,6 +1003,52 @@ static int DetectByteMathPacket02(void)
PASS;
}

/**
* \test A payload-supplied shift count of 64 or more yields 0 instead of
* shifting a uint64_t by its own width.
*/
static int DetectByteMathPacket03(void)
{
/* byte 0 is the shift count (64), byte 1 the value shifted, byte 2 the
* expected result */
uint8_t buf[] = { 0x40, 0xff, 0x00 };

Packet *p = UTHBuildPacket(buf, sizeof(buf), IPPROTO_UDP);
FAIL_IF_NULL(p);

/* 0xff >> 64 is 0 */
FAIL_IF_NOT(UTHPacketMatchSig(p, "alert udp any any -> any any "
"(byte_extract: 1, 0, shift;"
"byte_math: bytes 1, offset 1, oper >>, rvalue shift, result "
"var;"
"byte_test: 1, =, var, 2;"
"sid:1;)"));
UTHFreePacket(p);

PASS;
}

/**
* \test A literal shift count of 64 or more is rejected at parse time.
*/
static int DetectByteMathParseTest17(void)
{
DetectByteMathData *bmd = DetectByteMathParse(
NULL, "bytes 4, offset 2, oper >>, rvalue 64, result foo", NULL, NULL);
FAIL_IF_NOT_NULL(bmd);

bmd = DetectByteMathParse(
NULL, "bytes 4, offset 2, oper <<, rvalue 64, result foo", NULL, NULL);
FAIL_IF_NOT_NULL(bmd);

bmd = DetectByteMathParse(
NULL, "bytes 4, offset 2, oper >>, rvalue 63, result foo", NULL, NULL);
FAIL_IF_NULL(bmd);
DetectByteMathFree(NULL, bmd);

PASS;
}

static int DetectByteMathContext01(void)
{
DetectEngineCtx *de_ctx = NULL;
Expand Down Expand Up @@ -1069,8 +1119,10 @@ static void DetectByteMathRegisterTests(void)
UtRegisterTest("DetectByteMathParseTest14", DetectByteMathParseTest14);
UtRegisterTest("DetectByteMathParseTest15", DetectByteMathParseTest15);
UtRegisterTest("DetectByteMathParseTest16", DetectByteMathParseTest16);
UtRegisterTest("DetectByteMathParseTest17", DetectByteMathParseTest17);
UtRegisterTest("DetectByteMathPacket01", DetectByteMathPacket01);
UtRegisterTest("DetectByteMathPacket02", DetectByteMathPacket02);
UtRegisterTest("DetectByteMathPacket03", DetectByteMathPacket03);
UtRegisterTest("DetectByteMathContext01", DetectByteMathContext01);
}
#endif /* UNITTESTS */
61 changes: 34 additions & 27 deletions src/source-erf-dag.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ NoErfDagSupportExit(ThreadVars *tv, const void *initdata, void **data)
/* Number of bytes per loop to process before fetching more data. */
#define BYTES_PER_LOOP (4 * 1024 * 1024) /* 4 MB */

#define ERF_EXT_LEN 8
#define ERF_ETH_PAD_LEN 2

extern uint32_t max_pending_packets;

typedef struct ErfDagThreadVars_ {
Expand Down Expand Up @@ -394,6 +397,10 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read)
while (((top - ewtn->btm) >= dag_record_size) &&
((processed + dag_record_size) < BYTES_PER_LOOP)) {

if (suricata_ctl_flags & SURICATA_STOP) {
SCReturnInt(TM_ECODE_OK);
}

/* Make sure we have at least one packet in the packet pool,
* to prevent us from alloc'ing packets at line rate. */
PacketPoolWait();
Expand All @@ -419,25 +426,25 @@ ProcessErfDagRecords(ErfDagThreadVars *ewtn, uint8_t *top, uint32_t *pkts_read)
processed += rlen;

/* Only support ethernet at this time. */
switch (hdr_type & 0x7f) {
case ERF_TYPE_PAD:
case ERF_TYPE_META:
/* Skip. */
continue;
case ERF_TYPE_DSM_COLOR_ETH:
case ERF_TYPE_COLOR_ETH:
case ERF_TYPE_COLOR_HASH_ETH:
/* In these types the color value overwrites the lctr
* (drop count). */
break;
case ERF_TYPE_ETH:
if (dr->lctr) {
StatsCounterAddI64(&ewtn->tv->stats, ewtn->drops, SCNtohs(dr->lctr));
}
break;
default:
SCLogError("Processing of DAG record type: %d not implemented.", dr->type);
SCReturnInt(TM_ECODE_FAILED);
switch (hdr_type & ERF_TYPE_MASK) {
case ERF_TYPE_PAD:
case ERF_TYPE_META:
/* Skip. */
continue;
case ERF_TYPE_DSM_COLOR_ETH:
case ERF_TYPE_COLOR_ETH:
case ERF_TYPE_COLOR_HASH_ETH:
/* In these types the color value overwrites the lctr
* (drop count). */
break;
case ERF_TYPE_ETH:
if (dr->lctr) {
StatsCounterAddI64(&ewtn->tv->stats, ewtn->drops, SCNtohs(dr->lctr));
}
break;
default:
SCLogError("Processing of DAG record type: %d not implemented.", dr->type);
SCReturnInt(TM_ECODE_FAILED);
}

err = ProcessErfDagRecord(ewtn, prec);
Expand All @@ -461,10 +468,10 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec)
{
SCEnter();

int wlen = 0;
int rlen = 0;
uint16_t wlen = 0;
uint16_t rlen = 0;
int hdr_num = 0;
char hdr_type = 0;
uint8_t hdr_type = 0;
dag_record_t *dr = (dag_record_t*)prec;
erf_payload_t *pload;
Packet *p;
Expand All @@ -474,23 +481,23 @@ ProcessErfDagRecord(ErfDagThreadVars *ewtn, char *prec)
rlen = SCNtohs(dr->rlen);

/* count extension headers */
while (hdr_type & 0x80) {
if (rlen < (dag_record_size + (hdr_num * 8))) {
while (hdr_type & ERF_TYPE_MORE_EXT) {
if (rlen < (dag_record_size + (hdr_num * ERF_EXT_LEN))) {
SCLogError("Insufficient captured packet length.");
SCReturnInt(TM_ECODE_FAILED);
}
hdr_type = prec[(dag_record_size + (hdr_num * 8))];
hdr_type = prec[(dag_record_size + (hdr_num * ERF_EXT_LEN))];
hdr_num++;
}

/* Check that the whole frame was captured */
if (rlen < (dag_record_size + (8 * hdr_num) + 2 + wlen)) {
if (rlen < (dag_record_size + (hdr_num * ERF_EXT_LEN) + ERF_ETH_PAD_LEN + wlen)) {
SCLogInfo("Incomplete frame captured.");
SCReturnInt(TM_ECODE_OK);
}

/* skip over extension headers */
pload = (erf_payload_t *)(prec + dag_record_size + (8 * hdr_num));
pload = (erf_payload_t *)(prec + dag_record_size + (hdr_num * ERF_EXT_LEN));

p = PacketGetFromQueueOrAlloc();
if (p == NULL) {
Expand Down
Loading
Loading