plugins/ndpi: guard against NULL f->storage in all callbacks
Some checks failed
builds / Prepare dependencies (push) Has been cancelled
builds / Prepare cbindgen (push) Has been cancelled
CodeQL (Rust/C) / Analyze (push) Has been cancelled
Nix Env Build / tests (push) Has been cancelled
Scan-build / Scan-build (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
builds / AlmaLinux 10 (schema, plugins) (push) Has been cancelled
builds / AlmaLinux 9 (schema, rust-checks) (push) Has been cancelled
builds / AlmaLinux 9 Test Templates (push) Has been cancelled
builds / Build RPMs (push) Has been cancelled
builds / AlmaLinux 8 (push) Has been cancelled
builds / CentOS Stream 9 (push) Has been cancelled
builds / Fedora 43 (Suricata Verify codecov) (push) Has been cancelled
builds / Fedora 43 (clang, debug, asan, wshadow, rust-strict, systemd) (push) Has been cancelled
builds / Fedora 43 (gcc, debug, flto, asan, wshadow, rust-strict) (push) Has been cancelled
builds / Fedora (non-root, debug, clang, asan, wshadow, rust-strict, no-ja) (push) Has been cancelled
builds / AlmaLinux 9 (no jansson) (push) Has been cancelled
builds / AlmaLinux 9 (Minimal/Recommended Build) (push) Has been cancelled
builds / Ubuntu 24.04 (cocci) (push) Has been cancelled
builds / Ubuntu 24.04 (RUSTC+CARGO vars) (push) Has been cancelled
builds / Ubuntu 24.04 (unittests coverage) (push) Has been cancelled
builds / Ubuntu 24.04 (unix socket mode coverage) (push) Has been cancelled
builds / Ubuntu 24.04 (afpacket and dpdk coverage) (push) Has been cancelled
builds / Ubuntu 24.04 (pcap unix socket ASAN) (push) Has been cancelled
builds / Ubuntu 24.04 (afpacket IPS tests in namespaces) (push) Has been cancelled
builds / Ubuntu 24.04 (afpacket and dpdk live tests with ASAN) (push) Has been cancelled
builds / Ubuntu 24.04 (fuzz corpus coverage) (push) Has been cancelled
builds / Coveralls finish (push) Has been cancelled
builds / Ubuntu 20.04 (-DNDEBUG) (push) Has been cancelled
builds / Ubuntu 20.04 (unsupported rust) (push) Has been cancelled
builds / Ubuntu 22.04 (Debug Validation) (push) Has been cancelled
builds / Ubuntu 22.04 (Fuzz) (push) Has been cancelled
builds / Ubuntu 22.04 (Netmap build) (push) Has been cancelled
builds / Ubuntu 22.04 (Minimal/Recommended Build) (push) Has been cancelled
builds / Ubuntu 22.04 (DPDK Build) (push) Has been cancelled
builds / Debian 12 (xdp) (push) Has been cancelled
builds / Debian 13 (xdp) (push) Has been cancelled
builds / Ubuntu 22.04 Dist Builder (push) Has been cancelled
builds / Debian 12 MSRV (push) Has been cancelled
builds / Debian 11 (push) Has been cancelled
builds / MacOS Latest (push) Has been cancelled
builds / Windows MSYS2 MINGW64 (NPcap) (push) Has been cancelled
builds / Windows MSYS2 MINGW64 (libpcap) (push) Has been cancelled
builds / Windows MSYS2 UCRT64 (libpcap) (push) Has been cancelled
builds / Windows MSYS2 MINGW64 (WinDivert) (push) Has been cancelled
builds / PF_RING (push) Has been cancelled

This commit is contained in:
Antoine Abou Faysal 2026-03-06 19:28:36 +02:00 committed by Victor Julien
parent a072ca02be
commit 29834e3917

View file

@ -58,31 +58,72 @@ typedef struct DetectnDPIRiskData_ {
bool negated;
} DetectnDPIRiskData;
/**
* Safe helper to get nDPI thread context. Returns NULL if storage
* is not available (e.g. thread storage not yet initialized).
*/
static inline struct NdpiThreadContext *NdpiGetThreadContext(ThreadVars *tv)
{
if (unlikely(tv == NULL || thread_storage_id.id < 0))
return NULL;
return ThreadGetStorageById(tv, thread_storage_id);
}
/**
* Safe helper to get nDPI flow context. Returns NULL if the flow
* or its storage is not available. Guards against the case where
* f->storage is NULL (uninitialized flow) which would crash inside
* StorageGetById.
*/
static inline struct NdpiFlowContext *NdpiGetFlowContext(const Flow *f)
{
if (unlikely(f == NULL || flow_storage_id.id < 0 || f->storage == NULL))
return NULL;
return FlowGetStorageById(f, flow_storage_id);
}
static void ThreadStorageFree(void *ptr)
{
SCLogDebug("Free'ing nDPI thread storage");
struct NdpiThreadContext *context = ptr;
ndpi_exit_detection_module(context->ndpi);
if (context == NULL)
return;
if (context->ndpi != NULL)
ndpi_exit_detection_module(context->ndpi);
SCFree(context);
}
static void FlowStorageFree(void *ptr)
{
struct NdpiFlowContext *ctx = ptr;
ndpi_flow_free(ctx->ndpi_flow);
if (ctx == NULL)
return;
if (ctx->ndpi_flow != NULL)
ndpi_flow_free(ctx->ndpi_flow);
SCFree(ctx);
}
static void OnFlowInit(ThreadVars *tv, Flow *f, const Packet *p, void *_data)
{
if (unlikely(f == NULL))
return;
if (unlikely(f->storage == NULL)) {
SCLogDebug("Flow %p has no storage, skipping nDPI init", f);
return;
}
struct NdpiFlowContext *flowctx = SCCalloc(1, sizeof(*flowctx));
if (flowctx == NULL) {
FatalError("Failed to allocate nDPI flow context");
SCLogDebug("Failed to allocate nDPI flow context");
return;
}
flowctx->ndpi_flow = ndpi_flow_malloc(SIZEOF_FLOW_STRUCT);
if (flowctx->ndpi_flow == NULL) {
FatalError("Failed to allocate nDPI flow");
SCLogDebug("Failed to allocate nDPI flow");
SCFree(flowctx);
return;
}
memset(flowctx->ndpi_flow, 0, SIZEOF_FLOW_STRUCT);
@ -100,12 +141,13 @@ static void OnFlowUpdate(ThreadVars *tv, Flow *f, Packet *p, void *_data)
uint16_t ip_len = 0;
void *ip_ptr = NULL;
struct NdpiThreadContext *threadctx = ThreadGetStorageById(tv, thread_storage_id);
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
struct NdpiThreadContext *threadctx = NdpiGetThreadContext(tv);
struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);
if (!threadctx->ndpi || !flowctx->ndpi_flow) {
if (threadctx == NULL || threadctx->ndpi == NULL)
return;
if (flowctx == NULL || flowctx->ndpi_flow == NULL)
return;
}
if (PacketIsIPv4(p)) {
const IPV4Hdr *ip4h = PacketGetIPv4(p);
@ -189,7 +231,7 @@ static int DetectnDPIProtocolPacketMatch(
SCReturnInt(0);
}
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);
if (flowctx == NULL) {
SCLogDebug("packet %" PRIu64 ": no flowctx", PcapPacketCntGet(p));
SCReturnInt(0);
@ -324,7 +366,7 @@ static int DetectnDPIRiskPacketMatch(
SCReturnInt(0);
}
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);
if (flowctx == NULL) {
SCLogDebug("packet %" PRIu64 ": no flowctx", PcapPacketCntGet(p));
SCReturnInt(0);
@ -337,6 +379,11 @@ static int DetectnDPIRiskPacketMatch(
SCReturnInt(0);
}
if (flowctx->ndpi_flow == NULL) {
SCLogDebug("packet %" PRIu64 ": ndpi_flow is NULL", PcapPacketCntGet(p));
SCReturnInt(0);
}
bool r = ((flowctx->ndpi_flow->risk & data->risk_mask) == data->risk_mask);
r = r ^ data->negated;
@ -382,6 +429,7 @@ static DetectnDPIRiskData *DetectnDPIRiskParse(const char *arg, bool negate)
SCLogError("unrecognized risk '%s', "
"please check ndpiReader -H for valid risk codes",
token);
SCFree(dup);
return NULL;
}
NDPI_SET_BIT(risk_mask, risk_id);
@ -454,23 +502,36 @@ static void EveCallback(ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder
return;
}
struct NdpiThreadContext *threadctx = ThreadGetStorageById(tv, thread_storage_id);
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
struct NdpiThreadContext *threadctx = NdpiGetThreadContext(tv);
if (threadctx == NULL || threadctx->ndpi == NULL) {
return;
}
struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);
if (flowctx == NULL || flowctx->ndpi_flow == NULL) {
return;
}
ndpi_serializer serializer;
char *buffer;
uint32_t buffer_len;
SCLogDebug("EveCallback: tv=%p, p=%p, f=%p", tv, p, f);
ndpi_init_serializer(&serializer, ndpi_serialization_format_inner_json);
if (ndpi_init_serializer(&serializer, ndpi_serialization_format_inner_json) != 0) {
SCLogDebug("Failed to initialize nDPI serializer");
return;
}
/* Use ndpi_dpi2json to get a JSON with nDPI metadata */
ndpi_dpi2json(threadctx->ndpi, flowctx->ndpi_flow, flowctx->detected_l7_protocol, &serializer);
buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len);
/* Inject the nDPI JSON to the JsonBuilder */
SCJbSetFormatted(jb, buffer);
if (buffer != NULL && buffer_len > 0) {
/* Inject the nDPI JSON to the JsonBuilder */
SCJbSetFormatted(jb, buffer);
}
ndpi_term_serializer(&serializer);
}