suricata
detect-sctp-chunk-data.c
Go to the documentation of this file.
1 /* Copyright (C) 2026 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * Implements sctp.chunk_data multi-buffer sticky buffer.
22  *
23  * Each SCTP DATA chunk payload in the packet is inspected as a
24  * separate buffer instance (not reassembled).
25  *
26  * Author: Giuseppe Longo <glongo@oisf.net>
27  */
28 
29 #include "suricata-common.h"
30 
31 #include "detect.h"
32 #include "detect-engine.h"
33 #include "detect-engine-buffer.h"
36 #include "detect-engine-mpm.h"
38 #include "detect-sctp-chunk-data.h"
39 #include "util-mpm.h"
40 #include "util-profiling.h"
41 
42 static int DetectSCTPChunkDataSetup(DetectEngineCtx *, Signature *, const char *);
43 
44 static int g_buffer_id = 0;
45 
46 /**
47  * \brief Get a multi-instance inspection buffer for a specific DATA chunk.
48  *
49  * \param det_ctx detection engine thread context
50  * \param transforms transforms to apply
51  * \param p packet
52  * \param list_id buffer list id
53  * \param local_id multi-instance buffer index and index into SCTPVars data_offsets/data_lens
54  *
55  * \retval buffer or NULL
56  */
57 static InspectionBuffer *GetBuffer(DetectEngineThreadCtx *det_ctx,
58  const DetectEngineTransforms *transforms, Packet *p, const int list_id,
59  const uint32_t local_id)
60 {
62 
63  InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id);
64  if (buffer == NULL)
65  return NULL;
66  if (buffer->initialized)
67  return buffer;
68 
69  const uint16_t offset = p->l4.vars.sctp.data_offsets[(uint8_t)local_id];
70  const uint16_t len = p->l4.vars.sctp.data_lens[(uint8_t)local_id];
71  if (len == 0) {
73  return NULL;
74  }
75 
76  const uint8_t *data = (const uint8_t *)PacketGetSCTP(p) + offset;
77  if ((data + (ptrdiff_t)len) > ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p))) {
78  SCLogDebug("data out of range: %p > %p", (data + (ptrdiff_t)len),
79  ((uint8_t *)GET_PKT_DATA(p) + (ptrdiff_t)GET_PKT_LEN(p)));
81  return NULL;
82  }
83 
84  InspectionBufferSetupMulti(det_ctx, buffer, transforms, data, len);
85  return buffer;
86 }
87 
88 /**
89  * \brief Custom packet inspection callback for sctp.chunk_data.
90  *
91  * Loops over all tracked DATA chunks, inspecting each as a separate buffer.
92  */
93 static int DetectEngineInspectSCTPChunkData(DetectEngineThreadCtx *det_ctx,
94  const DetectEnginePktInspectionEngine *engine, const Signature *s, Packet *p,
95  uint8_t *_alert_flags)
96 {
97  if (!PacketIsSCTP(p))
99 
100  const uint8_t cnt = p->l4.vars.sctp.data_chunk_cnt;
101  if (cnt == 0)
103 
104  const int list_id = engine->sm_list;
105  const DetectEngineTransforms *transforms = NULL;
106  if (!engine->mpm) {
107  transforms = engine->v1.transforms;
108  }
109 
110  for (uint8_t i = 0; i < cnt; i++) {
111  InspectionBuffer *buffer = GetBuffer(det_ctx, transforms, p, list_id, (uint32_t)i);
112  if (buffer == NULL || buffer->inspect == NULL)
113  continue;
114 
115  if (DetectEngineContentInspectionBuffer(det_ctx->de_ctx, det_ctx, s, engine->smd, p,
118  }
119  }
120 
122 }
123 
125  int list_id;
126  const MpmCtx *mpm_ctx;
129 
130 /**
131  * \brief Prefilter callback: run MPM on each DATA chunk buffer.
132  */
133 static void PrefilterMpmSCTPChunkDataPkt(
134  DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
135 {
136  if (!PacketIsSCTP(p))
137  return;
138 
139  const uint8_t cnt = p->l4.vars.sctp.data_chunk_cnt;
140  if (cnt == 0)
141  return;
142 
144  const MpmCtx *mpm_ctx = ctx->mpm_ctx;
145  const int list_id = ctx->list_id;
146 
147  for (uint8_t i = 0; i < cnt; i++) {
148  InspectionBuffer *buffer = GetBuffer(det_ctx, ctx->transforms, p, list_id, (uint32_t)i);
149  if (buffer == NULL || buffer->inspect == NULL)
150  continue;
151 
152  if (buffer->inspect_len >= mpm_ctx->minlen) {
153  (void)mpm_table[mpm_ctx->mpm_type].Search(
154  mpm_ctx, &det_ctx->mtc, &det_ctx->pmq, buffer->inspect, buffer->inspect_len);
155  PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len);
156  }
157  }
158 }
159 
160 static void PrefilterMpmSCTPChunkDataFree(void *ptr)
161 {
162  SCFree(ptr);
163 }
164 
165 static int PrefilterSCTPChunkDataRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
166  MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id)
167 {
168  PrefilterMpmSCTPChunkData *pectx = SCCalloc(1, sizeof(*pectx));
169  if (pectx == NULL)
170  return -1;
171  pectx->list_id = list_id;
172  pectx->mpm_ctx = mpm_ctx;
173  pectx->transforms = &mpm_reg->transforms;
174 
175  return PrefilterAppendEngine(de_ctx, sgh, PrefilterMpmSCTPChunkDataPkt, 0,
176  SIGNATURE_HOOK_PKT_NOT_SET, pectx, PrefilterMpmSCTPChunkDataFree, mpm_reg->pname);
177 }
178 
180 {
181  sigmatch_table[DETECT_SCTP_CHUNK_DATA].name = "sctp.chunk_data";
183  "sticky buffer to match on each SCTP DATA chunk payload";
184  sigmatch_table[DETECT_SCTP_CHUNK_DATA].url = "/rules/sctp-keywords.html#sctp-chunk-data";
185  sigmatch_table[DETECT_SCTP_CHUNK_DATA].Setup = DetectSCTPChunkDataSetup;
187 
188  g_buffer_id = DetectBufferTypeRegister("sctp.chunk_data");
189  BUG_ON(g_buffer_id < 0);
190 
191  DetectBufferTypeSupportsPacket("sctp.chunk_data");
192  DetectBufferTypeSupportsMultiInstance("sctp.chunk_data");
193 
194  DetectPktMpmRegister("sctp.chunk_data", 2, PrefilterSCTPChunkDataRegister, NULL);
195 
196  DetectPktInspectEngineRegister("sctp.chunk_data", NULL, DetectEngineInspectSCTPChunkData);
197 }
198 
199 /**
200  * \brief setup sctp.chunk_data sticky buffer
201  *
202  * \param de_ctx pointer to the Detection Engine Context
203  * \param s pointer to the current Signature
204  * \param _unused unused
205  *
206  * \retval 0 on Success
207  * \retval -1 on Failure
208  */
209 static int DetectSCTPChunkDataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *_unused)
210 {
212  return -1;
213 
215 
216  if (SCDetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
217  return -1;
218 
219  return 0;
220 }
SigTableElmt_::url
const char * url
Definition: detect.h:1512
len
uint8_t len
Definition: app-layer-dnp3.h:2
MpmCtx_::mpm_type
uint8_t mpm_type
Definition: util-mpm.h:99
detect-engine.h
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect-engine-register.h:311
SigTableElmt_::desc
const char * desc
Definition: detect.h:1511
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
DetectEnginePktInspectionEngine
Definition: detect.h:484
SigTableElmt_::name
const char * name
Definition: detect.h:1509
InspectionBuffer::initialized
bool initialized
Definition: detect-engine-inspect-buffer.h:38
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1679
DetectEngineTransforms
Definition: detect.h:391
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1500
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
DetectPktMpmRegister
void DetectPktMpmRegister(const char *name, int priority, int(*PrefilterRegister)(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id), InspectionBufferGetPktDataPtr GetData)
register a MPM engine
Definition: detect-engine-mpm.c:598
detect-sctp-chunk-data.h
InspectionBuffer
Definition: detect-engine-inspect-buffer.h:34
PrefilterAppendEngine
int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterPktFn PrefilterFunc, SignatureMask mask, enum SignatureHookPkt hook, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
Definition: detect-engine-prefilter.c:285
PrefilterMpmSCTPChunkData::list_id
int list_id
Definition: detect-sctp-chunk-data.c:125
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1399
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:973
DetectEnginePktInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:485
SIGNATURE_HOOK_PKT_NOT_SET
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition: detect.h:540
DetectBufferTypeSupportsMultiInstance
void DetectBufferTypeSupportsMultiInstance(const char *name)
Definition: detect-engine.c:1334
DetectBufferMpmRegistry_
one time registration of keywords at start up
Definition: detect.h:770
SCDetectBufferSetActiveList
int SCDetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int list)
Definition: detect-engine-buffer.c:29
p
Packet * p
Definition: fuzz_iprep.c:21
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1491
DetectBufferMpmRegistry_::transforms
DetectEngineTransforms transforms
Definition: detect.h:783
detect-engine-prefilter.h
PrefilterMpmSCTPChunkData::mpm_ctx
const MpmCtx * mpm_ctx
Definition: detect-sctp-chunk-data.c:126
DetectEnginePktInspectionEngine::transforms
const DetectEngineTransforms * transforms
Definition: detect.h:493
DetectBufferTypeSupportsPacket
void DetectBufferTypeSupportsPacket(const char *name)
Definition: detect-engine.c:1354
DETECT_SCTP_CHUNK_DATA
@ DETECT_SCTP_CHUNK_DATA
Definition: detect-engine-register.h:58
SCTPVars_::data_offsets
uint16_t data_offsets[SCTP_MAX_DATA_CHUNKS]
Definition: decode-sctp.h:88
SCTP_MAX_DATA_CHUNKS
#define SCTP_MAX_DATA_CHUNKS
Definition: decode-sctp.h:42
detect-engine-inspect-buffer.h
DetectBufferMpmRegistry_::pname
char pname[DETECT_PROFILE_NAME_LEN]
Definition: detect.h:772
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:22
DetectEnginePktInspectionEngine::sm_list
uint16_t sm_list
Definition: detect.h:487
DetectEngineThreadCtx_
Definition: detect.h:1291
DetectPktInspectEngineRegister
void DetectPktInspectEngineRegister(const char *name, InspectionBufferGetPktDataPtr GetPktData, InspectionBufferPktInspectFunc Callback)
register inspect engine at start up time
Definition: detect-engine.c:156
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:210
detect-engine-mpm.h
detect.h
DETECT_ENGINE_INSPECT_SIG_MATCH
#define DETECT_ENGINE_INSPECT_SIG_MATCH
Definition: detect-engine-state.h:41
MpmCtx_::minlen
uint16_t minlen
Definition: util-mpm.h:108
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:325
util-profiling.h
Signature_::flags
uint32_t flags
Definition: detect.h:676
Packet_
Definition: decode.h:515
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:209
Packet_::l4
struct PacketL4 l4
Definition: decode.h:615
PrefilterMpmSCTPChunkData::transforms
const DetectEngineTransforms * transforms
Definition: detect-sctp-chunk-data.c:127
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:186
DetectEngineThreadCtx_::mtc
MpmThreadCtx mtc
Definition: detect.h:1395
detect-engine-content-inspection.h
DetectSCTPChunkDataRegister
void DetectSCTPChunkDataRegister(void)
Definition: detect-sctp-chunk-data.c:179
PacketL4::L4Vars::sctp
SCTPVars sctp
Definition: decode.h:494
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
PREFILTER_PROFILING_ADD_BYTES
#define PREFILTER_PROFILING_ADD_BYTES(det_ctx, bytes)
Definition: util-profiling.h:286
Packet_::flow
struct Flow_ * flow
Definition: decode.h:563
util-mpm.h
DetectBufferTypeRegister
int DetectBufferTypeRegister(const char *name)
Definition: detect-engine.c:1320
suricata-common.h
DetectEnginePktInspectionEngine::v1
struct DetectEnginePktInspectionEngine::@85 v1
detect-engine-buffer.h
Signature_::proto
DetectProto * proto
Definition: detect.h:694
DETECT_ENGINE_CONTENT_INSPECTION_MODE_HEADER
@ DETECT_ENGINE_CONTENT_INSPECTION_MODE_HEADER
Definition: detect-engine-content-inspection.h:33
DETECT_ENGINE_INSPECT_SIG_NO_MATCH
#define DETECT_ENGINE_INSPECT_SIG_NO_MATCH
Definition: detect-engine-state.h:40
InspectionBuffer::inspect_len
uint32_t inspect_len
Definition: detect-engine-inspect-buffer.h:37
InspectionBuffer::inspect
const uint8_t * inspect
Definition: detect-engine-inspect-buffer.h:35
PrefilterMpmSCTPChunkData
Definition: detect-sctp-chunk-data.c:124
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Signature_
Signature container.
Definition: detect.h:675
SIGMATCH_INFO_STICKY_BUFFER
#define SIGMATCH_INFO_STICKY_BUFFER
Definition: detect-engine-register.h:333
mpm_table
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.c:47
DetectEngineThreadCtx_::de_ctx
DetectEngineCtx * de_ctx
Definition: detect.h:1414
InspectionBufferSetupMultiEmpty
void InspectionBufferSetupMultiEmpty(InspectionBuffer *buffer)
setup the buffer empty
Definition: detect-engine-inspect-buffer.c:144
DetectEngineContentInspectionBuffer
bool DetectEngineContentInspectionBuffer(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Packet *p, Flow *f, const InspectionBuffer *b, const enum DetectContentInspectionType inspection_mode)
wrapper around DetectEngineContentInspectionInternal to return true/false only
Definition: detect-engine-content-inspection.c:772
IPPROTO_SCTP
#define IPPROTO_SCTP
Definition: decode.h:1272
DetectEnginePktInspectionEngine::mpm
bool mpm
Definition: detect.h:486
MpmCtx_
Definition: util-mpm.h:97
SCTPVars_::data_lens
uint16_t data_lens[SCTP_MAX_DATA_CHUNKS]
Definition: decode-sctp.h:89
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
InspectionBufferSetupMulti
void InspectionBufferSetupMulti(DetectEngineThreadCtx *det_ctx, InspectionBuffer *buffer, const DetectEngineTransforms *transforms, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
Definition: detect-engine-inspect-buffer.c:157
PacketL4::vars
union PacketL4::L4Vars vars
InspectionBufferMultipleForListGet
InspectionBuffer * InspectionBufferMultipleForListGet(DetectEngineThreadCtx *det_ctx, const int list_id, const uint32_t local_id)
for a InspectionBufferMultipleForList get a InspectionBuffer
Definition: detect-engine-inspect-buffer.c:76
PrefilterMpmSCTPChunkData
struct PrefilterMpmSCTPChunkData PrefilterMpmSCTPChunkData
DetectProtoContainsProto
int DetectProtoContainsProto(const DetectProto *dp, int proto)
see if a DetectProto contains a certain proto
Definition: detect-engine-proto.c:115
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:253
SCTPVars_::data_chunk_cnt
uint8_t data_chunk_cnt
Definition: decode-sctp.h:83