Skip to content

Use-after-free: KeyDB does not remove module cluster message receivers on MODULE UNLOAD #980

Description

@entropy1337

Summary
When a module registers a cluster message receiver (RM_RegisterClusterMessageReceiver), an entry is stored in the global clusterReceivers[] list holding the module handle and a callback pointer into the module's .so. KeyDB's module-unload path (moduleUnload, src/module.cpp:8806) cleans up commands, shared APIs, notifications, etc., but never removes the module's cluster receivers. After MODULE UNLOAD, clusterReceivers[type] still points at a receiver whose module/callback reference the freed module and the dlclose'd .so. The next CLUSTERMSG_TYPE_MODULE packet of that type → moduleCallClusterReceivers dereferences the freed module and calls the stale callback → use-after-free.

Affected version
KeyDB @603ebb27fb (2024-04-04, dev "255.255.255"). Present since the Redis fork point; KeyDB is frozen at ~2024 and never took the Valkey fix (#4360). Confirm the affected release range (KeyDB 6.x) with the vendor.

Technical details
moduleUnload (src/module.cpp:8806+) calls moduleUnregisterCommands, moduleUnregisterSharedAPI, moduleUnsubscribeNotifications, ... — there is no clusterReceivers cleanup anywhere in the unload path (the only references to clusterReceivers are the register/dispatch sites at module.cpp:6184–6241). So the receiver node survives (leaked-but-live) with dangling module/callback.

Proof of concept
Dynamically reproduced on a 2-node ASan KeyDB cluster (@603ebb27, built SANITIZE=address MALLOC=libc BUILD_TLS=no NO_MOTD=yes):

Both nodes --loadmodule uaftest.so (registers a cluster receiver for type 42 + a sendbad command that broadcasts a type-42 cluster message).
CLUSTER MEET; wait for full connectivity (both nodes connected, no handshake).
MODULE UNLOAD uaftest on node1 → clusterReceivers[42] dangles.
sendbad on node2 → broadcasts a type-42 cluster message.
node1 crashes — SIGSEGV on the cluster-message thread executing the dlclose'd module's callback: Module uaftest unloaded → crashed by signal: 11 ... Crashed running the instruction at: 0x.
(evidence/node1-crash-backtrace.txt; POC/uaftest.c; POC/repro-2node-cluster.sh.) Matches the ASan-confirmed Redis finding ID-REDIS-CLUSTERRECV-UNLOAD-UAF-01.

Activity

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