java-topology/defects/valkey/patch/0002-acl-upcoming-channels-dict.patch

77 lines
2.8 KiB
Diff
Raw 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.

# UNDF: UNDF-2026-000000327
From b83209d Mon Sep 17 00:00:00 2001
Subject: [PATCH] acl: replace upcoming channel list with dict for O(1) lookup
CWE-407: getUpcomingChannelList builds a linked list of all channel patterns
from 'new' user's selectors, then calls listSearchKey (O(n)) for each pattern
in 'original' user's selectors. Total cost O((S×C)²) where S=selectors,
C=channels per selector.
Fix: replace the `upcoming` linked list with a dict keyed on channel-pattern
sds values. Building the dict is O(S×C). Each lookup becomes O(1).
Total cost: O(S×C).
--- a/src/acl.c
+++ b/src/acl.c
@@ -1913,6 +1913,8 @@ list *getUpcomingChannelList(user *new, user *original) {
list *getUpcomingChannelList(user *new, user *original) {
listIter li, lpi;
listNode *ln, *lpn;
+ dict *upcoming_ht = NULL; /* CWE-407: O(1) membership check */
/* Optimization: we check if any selector has all channel permissions. */
listRewind(new->selectors,&li);
@@ -1924,22 +1924,23 @@ list *getUpcomingChannelList(user *new, user *original) {
if (s->flags & SELECTOR_FLAG_ALLCHANNELS) return NULL;
}
- list *upcoming = listCreate();
+ /* Build hash set of all channel patterns the new user may access. */
+ upcoming_ht = dictCreate(&sdsReplyDictType);
listRewind(new->selectors,&li);
while((ln = listNext(&li))) {
aclSelector *s = (aclSelector *) listNodeValue(ln);
listRewind(s->channels, &lpi);
while((lpn = listNext(&lpi))) {
- listAddNodeTail(upcoming, listNodeValue(lpn));
+ /* key is the channel sds; value unused — use dict as a set */
+ dictAdd(upcoming_ht, listNodeValue(lpn), NULL);
}
}
int match = 1;
listRewind(original->selectors,&li);
while((ln = listNext(&li)) && match) {
aclSelector *s = (aclSelector *) listNodeValue(ln);
if (s->flags & SELECTOR_FLAG_ALLCHANNELS) {
match = 0;
break;
}
listRewind(s->channels, &lpi);
while((lpn = listNext(&lpi)) && match) {
- if (!listSearchKey(upcoming, listNodeValue(lpn))) {
+ if (dictFind(upcoming_ht, listNodeValue(lpn)) == NULL) {
match = 0;
break;
}
}
}
if (match) {
- listRelease(upcoming);
+ dictRelease(upcoming_ht);
return NULL;
}
- return upcoming;
+ /* Caller needs the channel list, not the dict. Rebuild list from dict. */
+ list *result = listCreate();
+ dictIterator *di = dictGetIterator(upcoming_ht);
+ dictEntry *de;
+ while ((de = dictNext(di)) != NULL) {
+ listAddNodeTail(result, dictGetKey(de));
+ }
+ dictReleaseIterator(di);
+ dictRelease(upcoming_ht);
+ return result;
}