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
This commit is contained in:
parent
b3842ab6b8
commit
9934133dcf
260 changed files with 18278 additions and 15 deletions
|
|
@ -0,0 +1,66 @@
|
|||
From 2ba0194 Mon Sep 17 00:00:00 2001
|
||||
Subject: [PATCH] t_set: promote listpack sets to temp dicts before SINTER loop
|
||||
|
||||
CWE-407: sinterGenericCommand performs O(N×M) membership checks when inner
|
||||
sets use OBJ_ENCODING_LISTPACK. Each setTypeIsMemberAux call dispatches to
|
||||
lpFind — an O(M) linear scan of the packed byte array. With the default
|
||||
set-max-listpack-entries=128 this yields 128×128=16,384 comparisons per
|
||||
SINTER instead of 128.
|
||||
|
||||
Fix: before the intersection loop, convert any LISTPACK-encoded inner set
|
||||
(sets[1..setnum-1]) into a temporary OBJ_ENCODING_HT robj. Membership
|
||||
checks become O(1) dictFind. The temporary objects are freed after the loop.
|
||||
The smallest set (sets[0], iterated, never probed) is left as-is.
|
||||
|
||||
Also applies to the SDIFF algorithm-1 inner loop in sunionDiffGenericCommand.
|
||||
|
||||
--- a/src/t_set.c
|
||||
+++ b/src/t_set.c
|
||||
@@ -1383,6 +1383,7 @@ void sinterGenericCommand(client *c, robj **setkeys,
|
||||
setTypeIterator si;
|
||||
robj *dstset = NULL;
|
||||
+ robj **tmp_ht = NULL; /* temp HT views of listpack inner sets */
|
||||
char *str;
|
||||
size_t len = 0;
|
||||
int64_t intobj = 0;
|
||||
@@ -1436,6 +1436,25 @@ void sinterGenericCommand(client *c, robj **setkeys,
|
||||
*/
|
||||
qsort(sets,setnum,sizeof(setopsrc),qsortCompareSetsByCardinality);
|
||||
|
||||
+ /* CWE-407 fix: promote listpack-encoded inner sets to temporary HT objects
|
||||
+ * so membership checks inside the loop below are O(1) not O(n). */
|
||||
+ if (setnum > 1) {
|
||||
+ tmp_ht = zcalloc(setnum * sizeof(robj *));
|
||||
+ for (j = 1; j < setnum; j++) {
|
||||
+ if (sets[j].set && sets[j].set->encoding == OBJ_ENCODING_LISTPACK) {
|
||||
+ robj *ht = createSetObject(); /* OBJ_ENCODING_HT */
|
||||
+ setTypeIterator sit;
|
||||
+ char *s; size_t slen; int64_t llv;
|
||||
+ int enc;
|
||||
+ setTypeInitIterator(&sit, sets[j].set);
|
||||
+ while ((enc = setTypeNext(&sit, &s, &slen, &llv)) != -1) {
|
||||
+ setTypeAddAux(ht, s, slen, llv, enc == OBJ_ENCODING_HT);
|
||||
+ }
|
||||
+ setTypeResetIterator(&sit);
|
||||
+ tmp_ht[j] = ht;
|
||||
+ sets[j].set = ht; /* redirect probe target */
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* The first thing we should output is the total number of elements...
|
||||
@@ -1477,6 +1497,15 @@ void sinterGenericCommand(client *c, robj **setkeys,
|
||||
}
|
||||
setTypeResetIterator(&si);
|
||||
|
||||
+ /* Free temporary HT objects and restore original set pointers. */
|
||||
+ if (tmp_ht) {
|
||||
+ for (j = 1; j < setnum; j++) {
|
||||
+ if (tmp_ht[j]) {
|
||||
+ decrRefCount(tmp_ht[j]);
|
||||
+ }
|
||||
+ }
|
||||
+ zfree(tmp_ht);
|
||||
+ }
|
||||
+
|
||||
/* Update the key sizes histogram. */
|
||||
76
defects/redis/patch/0002-acl-upcoming-channels-dict.patch
Normal file
76
defects/redis/patch/0002-acl-upcoming-channels-dict.patch
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
From 2ba0194 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue