detect: fix multi inspect buffer issue; clean up

Fix multi inspect buffer API causing cleanup logic in the single
inspect buffer paths. This could lead to a buffer overrun in the
"to clear" logic.

Multi buffers now use InspectionBufferSetupMulti instead of
InspectionBuffer. This is enforced by a check in debug validation.

Simplify the multi inspect buffer setup code and update the callers.
pull/6261/head
Victor Julien 4 years ago
parent 23d7beb458
commit 3dc50322db

@ -78,8 +78,8 @@ static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -91,8 +91,7 @@ static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx,
&data, &data_len) == 0) { &data, &data_len) == 0) {
return NULL; return NULL;
} }
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); InspectionBufferSetupMulti(buffer, transforms, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -76,6 +76,7 @@
#include "util-device.h" #include "util-device.h"
#include "util-var-name.h" #include "util-var-name.h"
#include "util-profiling.h" #include "util-profiling.h"
#include "util-validate.h"
#include "tm-threads.h" #include "tm-threads.h"
#include "runmodes.h" #include "runmodes.h"
@ -1008,12 +1009,26 @@ InspectionBuffer *InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int
return &det_ctx->inspect.buffers[list_id]; return &det_ctx->inspect.buffers[list_id];
} }
static InspectionBufferMultipleForList *InspectionBufferGetMulti(
DetectEngineThreadCtx *det_ctx, const int list_id)
{
InspectionBufferMultipleForList *buffer = &det_ctx->multi_inspect.buffers[list_id];
if (!buffer->init) {
det_ctx->multi_inspect.to_clear_queue[det_ctx->multi_inspect.to_clear_idx++] = list_id;
buffer->init = 1;
}
return buffer;
}
/** \brief for a InspectionBufferMultipleForList get a InspectionBuffer /** \brief for a InspectionBufferMultipleForList get a InspectionBuffer
* \param fb the multiple buffer array * \param fb the multiple buffer array
* \param local_id the index to get a buffer * \param local_id the index to get a buffer
* \param buffer the inspect buffer or NULL in case of error */ * \param buffer the inspect buffer or NULL in case of error */
InspectionBuffer *InspectionBufferMultipleForListGet(InspectionBufferMultipleForList *fb, uint32_t local_id) InspectionBuffer *InspectionBufferMultipleForListGet(
DetectEngineThreadCtx *det_ctx, const int list_id, const uint32_t local_id)
{ {
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
if (local_id >= fb->size) { if (local_id >= fb->size) {
uint32_t old_size = fb->size; uint32_t old_size = fb->size;
uint32_t new_size = local_id + 1; uint32_t new_size = local_id + 1;
@ -1035,16 +1050,9 @@ InspectionBuffer *InspectionBufferMultipleForListGet(InspectionBufferMultipleFor
fb->max = MAX(fb->max, local_id); fb->max = MAX(fb->max, local_id);
InspectionBuffer *buffer = &fb->inspection_buffers[local_id]; InspectionBuffer *buffer = &fb->inspection_buffers[local_id];
SCLogDebug("using file_data buffer %p", buffer); SCLogDebug("using file_data buffer %p", buffer);
return buffer; #ifdef DEBUG_VALIDATION
} buffer->multi = true;
#endif
InspectionBufferMultipleForList *InspectionBufferGetMulti(DetectEngineThreadCtx *det_ctx, const int list_id)
{
InspectionBufferMultipleForList *buffer = &det_ctx->multi_inspect.buffers[list_id];
if (!buffer->init) {
det_ctx->multi_inspect.to_clear_queue[det_ctx->multi_inspect.to_clear_idx++] = list_id;
buffer->init = 1;
}
return buffer; return buffer;
} }
@ -1057,10 +1065,23 @@ void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size)
} }
} }
/** \brief setup the buffer with our initial data */
void InspectionBufferSetupMulti(InspectionBuffer *buffer, const DetectEngineTransforms *transforms,
const uint8_t *data, const uint32_t data_len)
{
DEBUG_VALIDATE_BUG_ON(!buffer->multi);
buffer->inspect = buffer->orig = data;
buffer->inspect_len = buffer->orig_len = data_len;
buffer->len = 0;
InspectionBufferApplyTransforms(buffer, transforms);
}
/** \brief setup the buffer with our initial data */ /** \brief setup the buffer with our initial data */
void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id, void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id,
InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len) InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
{ {
DEBUG_VALIDATE_BUG_ON(buffer->multi);
if (buffer->inspect == NULL) { if (buffer->inspect == NULL) {
#ifdef UNITTESTS #ifdef UNITTESTS
if (det_ctx && list_id != -1) if (det_ctx && list_id != -1)

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2010 Open Information Security Foundation /* Copyright (C) 2007-2021 Open Information Security Foundation
* *
* You can copy, redistribute or modify this Program under the terms of * You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free * the GNU General Public License version 2 as published by the Free
@ -40,8 +40,10 @@ bool DetectBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_list,
const uint8_t *content, uint16_t content_len, const char **namestr); const uint8_t *content, uint16_t content_len, const char **namestr);
void InspectionBufferClean(DetectEngineThreadCtx *det_ctx); void InspectionBufferClean(DetectEngineThreadCtx *det_ctx);
InspectionBuffer *InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id); InspectionBuffer *InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id);
InspectionBuffer *InspectionBufferMultipleForListGet(InspectionBufferMultipleForList *fb, uint32_t local_id); void InspectionBufferSetupMulti(InspectionBuffer *buffer, const DetectEngineTransforms *transforms,
InspectionBufferMultipleForList *InspectionBufferGetMulti(DetectEngineThreadCtx *det_ctx, const int list_id); const uint8_t *data, const uint32_t data_len);
InspectionBuffer *InspectionBufferMultipleForListGet(
DetectEngineThreadCtx *det_ctx, const int list_id, uint32_t local_id);
int DetectBufferTypeRegister(const char *name); int DetectBufferTypeRegister(const char *name);
int DetectBufferTypeGetByName(const char *name); int DetectBufferTypeGetByName(const char *name);

@ -488,8 +488,7 @@ static inline InspectionBuffer *FiledataWithXformsGetDataCallback(DetectEngineTh
const DetectEngineTransforms *transforms, const int list_id, int local_file_id, const DetectEngineTransforms *transforms, const int list_id, int local_file_id,
InspectionBuffer *base_buffer, const bool first) InspectionBuffer *base_buffer, const bool first)
{ {
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_file_id);
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, local_file_id);
if (buffer == NULL) { if (buffer == NULL) {
SCLogDebug("list_id: %d: no buffer", list_id); SCLogDebug("list_id: %d: no buffer", list_id);
return NULL; return NULL;
@ -499,9 +498,8 @@ static inline InspectionBuffer *FiledataWithXformsGetDataCallback(DetectEngineTh
return buffer; return buffer;
} }
InspectionBufferSetup(det_ctx, list_id, buffer, base_buffer->inspect, base_buffer->inspect_len); InspectionBufferSetupMulti(buffer, transforms, base_buffer->inspect, base_buffer->inspect_len);
buffer->inspect_offset = base_buffer->inspect_offset; buffer->inspect_offset = base_buffer->inspect_offset;
InspectionBufferApplyTransforms(buffer, transforms);
SCLogDebug("xformed buffer %p size %u", buffer, buffer->inspect_len); SCLogDebug("xformed buffer %p size %u", buffer, buffer->inspect_len);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }
@ -514,9 +512,8 @@ static InspectionBuffer *FiledataGetDataCallback(DetectEngineThreadCtx *det_ctx,
SCLogDebug( SCLogDebug(
"starting: list_id %d base_id %d first %s", list_id, base_id, first ? "true" : "false"); "starting: list_id %d base_id %d first %s", list_id, base_id, first ? "true" : "false");
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, base_id); InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, base_id, local_file_id);
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, local_file_id); SCLogDebug("base: buffer %p", buffer);
SCLogDebug("base: fb %p buffer %p", fb, buffer);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (base_id != list_id && buffer->inspect != NULL) { if (base_id != list_id && buffer->inspect != NULL) {
@ -568,7 +565,7 @@ static InspectionBuffer *FiledataGetDataCallback(DetectEngineThreadCtx *det_ctx,
StreamingBufferGetDataAtOffset(cur_file->sb, StreamingBufferGetDataAtOffset(cur_file->sb,
&data, &data_len, &data, &data_len,
cur_file->content_inspected); cur_file->content_inspected);
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); InspectionBufferSetupMulti(buffer, NULL, data, data_len);
SCLogDebug("[list %d] [before] buffer offset %" PRIu64 "; buffer len %" PRIu32 SCLogDebug("[list %d] [before] buffer offset %" PRIu64 "; buffer len %" PRIu32
"; data_len %" PRIu32 "; file_size %" PRIu64, "; data_len %" PRIu32 "; file_size %" PRIu64,
list_id, buffer->inspect_offset, buffer->inspect_len, data_len, file_size); list_id, buffer->inspect_offset, buffer->inspect_len, data_len, file_size);

@ -438,8 +438,7 @@ static InspectionBuffer *FilemagicGetDataCallback(DetectEngineThreadCtx *det_ctx
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_file_id);
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, local_file_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -461,8 +460,7 @@ static InspectionBuffer *FilemagicGetDataCallback(DetectEngineThreadCtx *det_ctx
const uint8_t *data = (const uint8_t *)cur_file->magic; const uint8_t *data = (const uint8_t *)cur_file->magic;
uint32_t data_len = (uint32_t)strlen(cur_file->magic); uint32_t data_len = (uint32_t)strlen(cur_file->magic);
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); InspectionBufferSetupMulti(buffer, transforms, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -357,8 +357,7 @@ static InspectionBuffer *FilenameGetDataCallback(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_file_id);
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, local_file_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -367,8 +366,7 @@ static InspectionBuffer *FilenameGetDataCallback(DetectEngineThreadCtx *det_ctx,
const uint8_t *data = cur_file->name; const uint8_t *data = cur_file->name;
uint32_t data_len = cur_file->name_len; uint32_t data_len = cur_file->name_len;
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); InspectionBufferSetupMulti(buffer, transforms, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -691,8 +691,8 @@ static InspectionBuffer *GetHttp2HNameData(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -825,8 +825,8 @@ static InspectionBuffer *GetHttp2HeaderData(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -840,8 +840,7 @@ static InspectionBuffer *GetHttp2HeaderData(DetectEngineThreadCtx *det_ctx,
if (b == NULL || b_len == 0) if (b == NULL || b_len == 0)
return NULL; return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); InspectionBufferSetupMulti(buffer, transforms, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -59,8 +59,8 @@ static InspectionBuffer *IkeVendorGetData(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -72,8 +72,7 @@ static InspectionBuffer *IkeVendorGetData(DetectEngineThreadCtx *det_ctx,
return NULL; return NULL;
} }
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); InspectionBufferSetupMulti(buffer, transforms, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -61,8 +61,8 @@ static InspectionBuffer *GetKrb5CNameData(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -76,8 +76,7 @@ static InspectionBuffer *GetKrb5CNameData(DetectEngineThreadCtx *det_ctx,
if (b == NULL || b_len == 0) if (b == NULL || b_len == 0)
return NULL; return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); InspectionBufferSetupMulti(buffer, transforms, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -61,8 +61,8 @@ static InspectionBuffer *GetKrb5SNameData(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -76,8 +76,7 @@ static InspectionBuffer *GetKrb5SNameData(DetectEngineThreadCtx *det_ctx,
if (b == NULL || b_len == 0) if (b == NULL || b_len == 0)
return NULL; return NULL;
InspectionBufferSetup(det_ctx, list_id, buffer, b, b_len); InspectionBufferSetupMulti(buffer, transforms, b, b_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -69,8 +69,8 @@ static InspectionBuffer *MQTTSubscribeTopicGetData(DetectEngineThreadCtx *det_ct
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -83,8 +83,7 @@ static InspectionBuffer *MQTTSubscribeTopicGetData(DetectEngineThreadCtx *det_ct
return NULL; return NULL;
} }
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); InspectionBufferSetupMulti(buffer, transforms, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }
@ -236,4 +235,4 @@ static int DetectMQTTSubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s,
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1; return -1;
return 0; return 0;
} }

@ -69,8 +69,8 @@ static InspectionBuffer *MQTTUnsubscribeTopicGetData(DetectEngineThreadCtx *det_
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
if (!first && buffer->inspect != NULL) if (!first && buffer->inspect != NULL)
@ -83,8 +83,7 @@ static InspectionBuffer *MQTTUnsubscribeTopicGetData(DetectEngineThreadCtx *det_
return NULL; return NULL;
} }
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len); InspectionBufferSetupMulti(buffer, transforms, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }
@ -236,4 +235,4 @@ static int DetectMQTTUnsubscribeTopicSetup(DetectEngineCtx *de_ctx, Signature *s
if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0) if (DetectSignatureSetAppProto(s, ALPROTO_MQTT) < 0)
return -1; return -1;
return 0; return 0;
} }

@ -137,8 +137,8 @@ static InspectionBuffer *TlsCertsGetData(DetectEngineThreadCtx *det_ctx,
{ {
SCEnter(); SCEnter();
InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id); InspectionBuffer *buffer =
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id); InspectionBufferMultipleForListGet(det_ctx, list_id, cbdata->local_id);
if (buffer == NULL) if (buffer == NULL)
return NULL; return NULL;
@ -151,16 +151,13 @@ static InspectionBuffer *TlsCertsGetData(DetectEngineThreadCtx *det_ctx,
if (cbdata->cert == NULL) { if (cbdata->cert == NULL) {
cbdata->cert = TAILQ_FIRST(&ssl_state->server_connp.certs); cbdata->cert = TAILQ_FIRST(&ssl_state->server_connp.certs);
} else { } else {
cbdata->cert = TAILQ_NEXT(cbdata->cert, next); cbdata->cert = TAILQ_NEXT(cbdata->cert, next);
} }
if (cbdata->cert == NULL) { if (cbdata->cert == NULL) {
return NULL; return NULL;
} }
InspectionBufferSetup( InspectionBufferSetupMulti(buffer, transforms, cbdata->cert->cert_data, cbdata->cert->cert_len);
det_ctx, list_id, buffer, cbdata->cert->cert_data, cbdata->cert->cert_len);
InspectionBufferApplyTransforms(buffer, transforms);
SCReturnPtr(buffer, "InspectionBuffer"); SCReturnPtr(buffer, "InspectionBuffer");
} }

@ -346,7 +346,9 @@ typedef struct InspectionBuffer {
uint64_t inspect_offset; uint64_t inspect_offset;
uint32_t inspect_len; /**< size of active data. See to ::len or ::orig_len */ uint32_t inspect_len; /**< size of active data. See to ::len or ::orig_len */
uint8_t flags; /**< DETECT_CI_FLAGS_* for use with DetectEngineContentInspection */ uint8_t flags; /**< DETECT_CI_FLAGS_* for use with DetectEngineContentInspection */
#ifdef DEBUG_VALIDATION
bool multi;
#endif
uint32_t len; /**< how much is in use */ uint32_t len; /**< how much is in use */
uint8_t *buf; uint8_t *buf;
uint32_t size; /**< size of the memory allocation */ uint32_t size; /**< size of the memory allocation */

Loading…
Cancel
Save