java-topology/docs/tickets/redis-0002-acl-upcoming-channel-quadratic.md
russell@unturf.com 9934133dcf whitepaper: 312 sites / 151 ecosystems — wave2+3 defect tables and PDF rebuild
Add 88 new defect entries to HIGH and MEDIUM tables:
  HIGH: mysql-0001/0002, mariadb-0001, redis-0001/0002, valkey-0001/0002, openvpn-0001,
        vlc-0001, prometheus-0001, otel-collector-0001, cockroachdb-0001..0004,
        tidb-0001..0008, kubernetes-0001/0002, go-0001, kotlin-0002, scala-0001,
        allegro5-0001, sdl2-0001, grafana-0001, clickhouse-0001, duckdb-0001,
        mongodb-0001, envoy-0001, istio-0001, cilium-0001, linkerd2-0001,
        linux-0001/0002/0003, tor-0002/0003, curl-0001, julia-0001, lua-0001,
        perl5-0001, nats-0001, spring-0003/0004, tomcat-0001, onos-0002, odl-0002

  MEDIUM: helm-0001, mariadb-0002, openssl-0001/0002, memcached-0001,
          cassandra-0001..0004, flink-0001, storm-0001/0002, zookeeper-0001..0003,
          pip-0001, gradle-0001, nginx-0001, haproxy-0001, caddy-0001, varnish-0001,
          ffmpeg-0001, gstreamer-0001, raylib-0001, love2d-0001, php-0001/0002,
          r-source-0001, cpython-0002, ruby-0001, rabbitmq-0003/0004, activemq-0001,
          ovs-0001, onos-0003, odl-0002, jetty-0001

PDF: 976K
2026-03-27 15:23:43 -04:00

60 lines
2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# redis-0002: getUpcomingChannelList O(S×C²) quadratic channel membership
**Target:** redis/redis
**Severity:** MEDIUM
**CWE:** CWE-407 (Inefficient Algorithmic Complexity)
**File:** `src/acl.c:1952` (`getUpcomingChannelList`)
**Status:** PATCHED
## Description
`getUpcomingChannelList(user *new, user *original)` builds a flat linked list
(`upcoming`) of all channel patterns from `new`'s selectors, then for each
channel pattern in `original`'s selectors calls `listSearchKey(upcoming, ...)`.
`listSearchKey` is an O(n) walk of the `upcoming` list. With S selectors and C
channel patterns per selector the `upcoming` list grows to S×C entries.
The outer loop also iterates S×C patterns.
Result: O((S×C)²) in the worst case — quadratic in total channel-pattern count.
In practice, heavily compartmentalized users (many selectors, many channel ACL
rules) hit this during `ACL SETUSER` and at any `SUBSCRIBE`/`PSUBSCRIBE` event
that triggers client-kill evaluation.
## Hot paths
- `ACL SETUSER` — triggers `killPubsubClientsIfNeeded`, which calls
`getUpcomingChannelList` for each affected client.
- `SUBSCRIBE` / `PSUBSCRIBE` evaluation when ACL rules restrict channels.
## Root cause
`src/acl.c:19351960`:
```c
list *upcoming = listCreate(); // O(S×C) entries
...
while((lpn = listNext(&lpi)) && match) {
if (!listSearchKey(upcoming, listNodeValue(lpn))) { // O(S×C) per call
match = 0;
```
## Fix
Replace the `upcoming` linked list with a hash table (`dictCreate` with
`dictTypeSds` or a simple `rax`). Build the set from `new`'s selectors, then
check each of `original`'s channel patterns with O(1) lookup. Total cost
becomes O(S×C) instead of O((S×C)²).
See patch: `defects/redis/patch/0002-acl-upcoming-channels-dict.patch`
## Also affects
- valkey/valkey — identical `getUpcomingChannelList` code path.
## Ops ratio (unit test)
S=4 selectors, C=50 channels each (200 total):
- slow ops: 200 × 200 = 40,000
- fast ops: 200 (one pass build) + 200 (O(1) lookups) = 400
- speedup: **100×**