Skip to content

Global-buffer-overflow in KeyDB module cluster message receivers #979

Description

@entropy1337

Summary
KeyDB stores module cluster-message receivers in static moduleClusterReceiver *clusterReceivers[UINT8_MAX]; (src/module.cpp:6184) — an array of 255 elements (indices 0..254). The cluster message type is a uint8_t (0..255). Both the register path (RM_RegisterClusterMessageReceiver) and the dispatch path (moduleCallClusterReceivers) index clusterReceivers[type] with the full 0..255 range, so type 255 reads/writes one element past the array — an out-of-bounds access on a global buffer. Cluster-bus reachable via a CLUSTERMSG_TYPE_MODULE packet with type 255 from a known peer → node crash (DoS).

Affected version
KeyDB @603ebb27fb (2024-04-04, dev "255.255.255"). KeyDB is frozen at ~2024 and never took the Valkey fix (#4410). This is the same off-by-one as the ASan-confirmed Redis finding (Valkey fixed both forks; KeyDB tracked neither).

Technical details
// src/module.cpp:6184
static moduleClusterReceiver *clusterReceivers[UINT8_MAX]; // 255 elements, idx 0..254

// dispatch (module.cpp:6188) -> clusterReceivers[type] (type up to 255)
// register (module.cpp:6212,6240)-> clusterReceivers[type] (type up to 255)

type == 255 indexes clusterReceivers[255], one past the end.

Proof of concept
A minimal module (POC/oobtest.c) registers a receiver for type 255:

RedisModule_RegisterClusterMessageReceiver(ctx, 255, dummy_cb);

Loaded on a cluster-enabled ASan build:

keydb-server --port 7711 --cluster-enabled yes --loadmodule ./oobtest.so

AddressSanitizer (evidence/asan-global-buffer-overflow.txt):

ERROR: AddressSanitizer: global-buffer-overflow ... at RM_RegisterClusterMessageReceiver module.cpp:6212
0x... is located 0 bytes to the right of global variable 'clusterReceivers'
defined in 'module.cpp:6184:31' of size 2040 (2040 = 255 * 8)
SUMMARY: AddressSanitizer: global-buffer-overflow module.cpp:6212

Attacker-reachable variant: the cluster bus reads type straight off the wire and passes it to moduleCallClusterReceivers → clusterReceivers[255] OOB read of a pointer then walked as a receiver list → crash / potential further deref.

Impact
CVSS 6.5 (AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H) — DoS (crash) of a cluster node. Escalation beyond DoS depends on the static memory adjacent to the array.

Remediation
clusterReceivers[UINT8_MAX + 1] (256 elements) and audit the unregister loop bound (mirror Valkey #4410).

Build / repro
make SANITIZE=address MALLOC=libc BUILD_TLS=no NO_MOTD=yes → src/keydb-server (ASan). gcc -I src -fPIC -shared -std=c99 oobtest.c -o oobtest.so (needs #define REDISMODULE_EXPERIMENTAL_API).

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