suricata
detect-engine-inspect-buffer.c
Go to the documentation of this file.
1 /* Copyright (C) 2025 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  * \author Victor Julien <victor@inliniac.net>
22  */
23 
24 #include "suricata-common.h"
26 #include "detect.h"
27 
28 #include "util-validate.h"
29 
31 {
32  /* single buffers */
33  for (uint32_t i = 0; i < det_ctx->inspect.to_clear_idx; i++) {
34  const uint32_t idx = det_ctx->inspect.to_clear_queue[i];
35  InspectionBuffer *buffer = &det_ctx->inspect.buffers[idx];
36  buffer->inspect = NULL;
37  buffer->initialized = false;
38  }
39  det_ctx->inspect.to_clear_idx = 0;
40 
41  /* multi buffers */
42  for (uint32_t i = 0; i < det_ctx->multi_inspect.to_clear_idx; i++) {
43  const uint32_t idx = det_ctx->multi_inspect.to_clear_queue[i];
44  InspectionBufferMultipleForList *mbuffer = &det_ctx->multi_inspect.buffers[idx];
45  for (uint32_t x = 0; x <= mbuffer->max; x++) {
46  InspectionBuffer *buffer = &mbuffer->inspection_buffers[x];
47  buffer->inspect = NULL;
48  buffer->initialized = false;
49  }
50  mbuffer->init = 0;
51  mbuffer->max = 0;
52  }
53  det_ctx->multi_inspect.to_clear_idx = 0;
54 }
55 
57 {
58  return &det_ctx->inspect.buffers[list_id];
59 }
60 
61 static InspectionBufferMultipleForList *InspectionBufferGetMulti(
62  DetectEngineThreadCtx *det_ctx, const int list_id)
63 {
64  InspectionBufferMultipleForList *buffer = &det_ctx->multi_inspect.buffers[list_id];
65  if (!buffer->init) {
66  det_ctx->multi_inspect.to_clear_queue[det_ctx->multi_inspect.to_clear_idx++] = list_id;
67  buffer->init = 1;
68  }
69  return buffer;
70 }
71 
72 /** \brief for a InspectionBufferMultipleForList get a InspectionBuffer
73  * \param fb the multiple buffer array
74  * \param local_id the index to get a buffer
75  * \param buffer the inspect buffer or NULL in case of error */
77  DetectEngineThreadCtx *det_ctx, const int list_id, const uint32_t local_id)
78 {
79  if (unlikely(local_id >= 1024)) {
81  return NULL;
82  }
83 
84  InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
85 
86  if (local_id >= fb->size) {
87  uint32_t old_size = fb->size;
88  uint32_t new_size = local_id + 1;
89  uint32_t grow_by = new_size - old_size;
90  SCLogDebug("size is %u, need %u, so growing by %u", old_size, new_size, grow_by);
91 
92  SCLogDebug("fb->inspection_buffers %p", fb->inspection_buffers);
93  void *ptr = SCRealloc(fb->inspection_buffers, (local_id + 1) * sizeof(InspectionBuffer));
94  if (ptr == NULL)
95  return NULL;
96 
97  InspectionBuffer *to_zero = (InspectionBuffer *)ptr + old_size;
98  SCLogDebug("ptr %p to_zero %p", ptr, to_zero);
99  memset((uint8_t *)to_zero, 0, (grow_by * sizeof(InspectionBuffer)));
100  fb->inspection_buffers = ptr;
101  fb->size = new_size;
102  }
103 
104  fb->max = MAX(fb->max, local_id);
105  InspectionBuffer *buffer = &fb->inspection_buffers[local_id];
106  SCLogDebug("using buffer %p", buffer);
107 #ifdef DEBUG_VALIDATION
108  buffer->multi = true;
109 #endif
110  return buffer;
111 }
112 
113 static inline void InspectionBufferApplyTransformsInternal(DetectEngineThreadCtx *det_ctx,
114  InspectionBuffer *buffer, const DetectEngineTransforms *transforms)
115 {
116  if (transforms) {
117  for (int i = 0; i < DETECT_TRANSFORMS_MAX; i++) {
118  const int id = transforms->transforms[i].transform;
119  if (id == 0)
120  break;
121  BUG_ON(sigmatch_table[id].Transform == NULL);
122  sigmatch_table[id].Transform(det_ctx, buffer, transforms->transforms[i].options);
123  SCLogDebug("applied transform %s", sigmatch_table[id].name);
124  }
125  }
126 }
127 
129  const DetectEngineTransforms *transforms)
130 {
131  InspectionBufferApplyTransformsInternal(det_ctx, buffer, transforms);
132 }
133 
134 void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size)
135 {
136  memset(buffer, 0, sizeof(*buffer));
137  buffer->buf = SCCalloc(initial_size, sizeof(uint8_t));
138  if (buffer->buf != NULL) {
139  buffer->size = initial_size;
140  }
141 }
142 
143 /** \brief setup the buffer empty */
145 {
146 #ifdef DEBUG_VALIDATION
148  DEBUG_VALIDATE_BUG_ON(!buffer->multi);
149 #endif
150  buffer->inspect = NULL;
151  buffer->inspect_len = 0;
152  buffer->len = 0;
153  buffer->initialized = true;
154 }
155 
156 /** \brief setup the buffer with our initial data */
158  const DetectEngineTransforms *transforms, const uint8_t *data, const uint32_t data_len)
159 {
160 #ifdef DEBUG_VALIDATION
161  DEBUG_VALIDATE_BUG_ON(!buffer->multi);
162 #endif
163  buffer->inspect = buffer->orig = data;
164  buffer->inspect_len = buffer->orig_len = data_len;
165  buffer->len = 0;
166  buffer->initialized = true;
167 
168  InspectionBufferApplyTransformsInternal(det_ctx, buffer, transforms);
169 }
170 
171 static inline void InspectionBufferSetupInternal(DetectEngineThreadCtx *det_ctx, const int list_id,
172  InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
173 {
174 #ifdef DEBUG_VALIDATION
175  DEBUG_VALIDATE_BUG_ON(buffer->multi);
176  DEBUG_VALIDATE_BUG_ON(buffer != InspectionBufferGet(det_ctx, list_id));
177 #endif
178  if (buffer->inspect == NULL) {
179 #ifdef UNITTESTS
180  if (det_ctx && list_id != -1)
181 #endif
182  det_ctx->inspect.to_clear_queue[det_ctx->inspect.to_clear_idx++] = list_id;
183  }
184  buffer->inspect = buffer->orig = data;
185  buffer->inspect_len = buffer->orig_len = data_len;
186  buffer->len = 0;
187  buffer->initialized = true;
188 }
189 /** \brief setup the buffer with our initial data */
190 void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id,
191  InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
192 {
193  InspectionBufferSetupInternal(det_ctx, list_id, buffer, data, data_len);
194 }
195 
196 /** \brief setup the buffer with our initial data */
198  InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len,
199  const DetectEngineTransforms *transforms)
200 {
201  InspectionBufferSetupInternal(det_ctx, list_id, buffer, data, data_len);
202  InspectionBufferApplyTransformsInternal(det_ctx, buffer, transforms);
203 }
204 
206 {
207  if (buffer->buf != NULL) {
208  SCFree(buffer->buf);
209  }
210  memset(buffer, 0, sizeof(*buffer));
211 }
212 
213 /**
214  * \brief make sure that the buffer has at least 'min_size' bytes
215  * Expand the buffer if necessary
216  */
217 uint8_t *SCInspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size)
218 {
219  if (likely(buffer->size >= min_size))
220  return buffer->buf;
221 
222  uint32_t new_size = (buffer->size == 0) ? 4096 : buffer->size;
223  while (new_size < min_size) {
224  new_size *= 2;
225  }
226 
227  void *ptr = SCRealloc(buffer->buf, new_size);
228  if (ptr != NULL) {
229  buffer->buf = ptr;
230  buffer->size = new_size;
231  } else {
232  return NULL;
233  }
234  return buffer->buf;
235 }
236 
237 void SCInspectionBufferTruncate(InspectionBuffer *buffer, uint32_t buf_len)
238 {
239  DEBUG_VALIDATE_BUG_ON(buffer->buf == NULL);
240  DEBUG_VALIDATE_BUG_ON(buf_len > buffer->size);
241  buffer->inspect = buffer->buf;
242  buffer->inspect_len = buf_len;
243  buffer->initialized = true;
244 }
245 
246 void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len)
247 {
248  SCInspectionBufferCheckAndExpand(buffer, buf_len);
249 
250  if (buffer->size) {
251  uint32_t copy_size = MIN(buf_len, buffer->size);
252  memcpy(buffer->buf, buf, copy_size);
253  buffer->inspect = buffer->buf;
254  buffer->inspect_len = copy_size;
255  buffer->initialized = true;
256  }
257 }
DETECT_EVENT_TOO_MANY_BUFFERS
@ DETECT_EVENT_TOO_MANY_BUFFERS
Definition: detect.h:1430
InspectionBufferApplyTransforms
void InspectionBufferApplyTransforms(DetectEngineThreadCtx *det_ctx, InspectionBuffer *buffer, const DetectEngineTransforms *transforms)
Definition: detect-engine-inspect-buffer.c:128
DetectEngineThreadCtx_::to_clear_idx
uint32_t to_clear_idx
Definition: detect.h:1256
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:155
InspectionBuffer::initialized
bool initialized
Definition: detect-engine-inspect-buffer.h:38
InspectionBufferCopy
void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len)
Definition: detect-engine-inspect-buffer.c:246
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
DetectEngineTransforms
Definition: detect.h:392
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
InspectionBufferClean
void InspectionBufferClean(DetectEngineThreadCtx *det_ctx)
Definition: detect-engine-inspect-buffer.c:30
InspectionBuffer
Definition: detect-engine-inspect-buffer.h:34
TransformData_::options
void * options
Definition: detect.h:389
InspectionBufferSetup
void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id, InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
setup the buffer with our initial data
Definition: detect-engine-inspect-buffer.c:190
InspectionBuffer::orig
const uint8_t * orig
Definition: detect-engine-inspect-buffer.h:48
DetectEngineSetEvent
void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e)
Definition: detect-engine.c:4795
MIN
#define MIN(x, y)
Definition: suricata-common.h:408
InspectionBuffer::size
uint32_t size
Definition: detect-engine-inspect-buffer.h:45
MAX
#define MAX(x, y)
Definition: suricata-common.h:412
InspectionBufferGet
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
Definition: detect-engine-inspect-buffer.c:56
InspectionBufferMultipleForList::init
uint32_t init
Definition: detect.h:384
DETECT_TRANSFORMS_MAX
#define DETECT_TRANSFORMS_MAX
Definition: detect.h:48
InspectionBuffer::orig_len
uint32_t orig_len
Definition: detect-engine-inspect-buffer.h:47
InspectionBufferMultipleForList::size
uint32_t size
Definition: detect.h:382
InspectionBufferMultipleForList
Definition: detect.h:380
detect-engine-inspect-buffer.h
InspectionBufferFree
void InspectionBufferFree(InspectionBuffer *buffer)
Definition: detect-engine-inspect-buffer.c:205
DetectEngineThreadCtx_
Definition: detect.h:1200
DetectEngineThreadCtx_::buffers
InspectionBuffer * buffers
Definition: detect.h:1254
detect.h
InspectionBuffer::buf
uint8_t * buf
Definition: detect-engine-inspect-buffer.h:44
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
name
const char * name
Definition: tm-threads.c:2123
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:393
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
DetectEngineThreadCtx_::to_clear_queue
uint32_t * to_clear_queue
Definition: detect.h:1257
suricata-common.h
InspectionBufferInit
void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size)
Definition: detect-engine-inspect-buffer.c:134
TransformData_::transform
int transform
Definition: detect.h:388
util-validate.h
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
InspectionBuffer::len
uint32_t len
Definition: detect-engine-inspect-buffer.h:43
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DetectEngineThreadCtx_::inspect
struct DetectEngineThreadCtx_::@98 inspect
InspectionBufferSetupAndApplyTransforms
void InspectionBufferSetupAndApplyTransforms(DetectEngineThreadCtx *det_ctx, const int list_id, InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len, const DetectEngineTransforms *transforms)
setup the buffer with our initial data
Definition: detect-engine-inspect-buffer.c:197
InspectionBufferSetupMultiEmpty
void InspectionBufferSetupMultiEmpty(InspectionBuffer *buffer)
setup the buffer empty
Definition: detect-engine-inspect-buffer.c:144
SCInspectionBufferCheckAndExpand
uint8_t * SCInspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size)
make sure that the buffer has at least 'min_size' bytes Expand the buffer if necessary
Definition: detect-engine-inspect-buffer.c:217
DetectEngineThreadCtx_::multi_inspect
struct DetectEngineThreadCtx_::@99 multi_inspect
likely
#define likely(expr)
Definition: util-optimize.h:32
id
uint32_t id
Definition: detect-flowbits.c:933
SigTableElmt_::Transform
void(* Transform)(DetectEngineThreadCtx *, InspectionBuffer *, void *context)
Definition: detect.h:1386
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
InspectionBufferMultipleForList::inspection_buffers
InspectionBuffer * inspection_buffers
Definition: detect.h:381
InspectionBufferMultipleForList::max
uint32_t max
Definition: detect.h:383
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
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
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
SCInspectionBufferTruncate
void SCInspectionBufferTruncate(InspectionBuffer *buffer, uint32_t buf_len)
Definition: detect-engine-inspect-buffer.c:237