java-topology/defects/caddy/patch/caddy-0001.patch
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
1.9 KiB
Diff

--- a/modules/caddyhttp/reverseproxy/selectionpolicies.go
+++ b/modules/caddyhttp/reverseproxy/selectionpolicies.go
@@ -1,6 +1,7 @@
package reverseproxy
import (
+ "sync/atomic"
"encoding/json"
"fmt"
"math/rand/v2"
@@ -30,6 +31,20 @@ import (
+// upstreamHashCache caches the xxhash of each upstream's stable string
+// representation. Populated at Provision time; cleared on config reload.
+// Key = upstream index in pool; value = xxhash of up.String().
+var upstreamHashCacheMu sync.RWMutex
+var upstreamHashCache = make(map[string]uint64) // up.String() → hash
+
+// getOrCacheUpstreamHash returns the cached xxhash of up.String(), computing
+// and storing it on the first call. O(1) amortised over the lifetime of a
+// config.
+func getOrCacheUpstreamHash(up *Upstream) uint64 {
+ key := up.String()
+ upstreamHashCacheMu.RLock()
+ h, ok := upstreamHashCache[key]
+ upstreamHashCacheMu.RUnlock()
+ if ok {
+ return h
+ }
+ h = hash(key)
+ upstreamHashCacheMu.Lock()
+ upstreamHashCache[key] = h
+ upstreamHashCacheMu.Unlock()
+ return h
+}
+
// hostByHashing returns an available host from pool based on a hashable string s.
func hostByHashing(pool []*Upstream, s string) *Upstream {
// Highest Random Weight (HRW, or "Rendezvous") hashing,
@@ -833,15 +855,17 @@ func hostByHashing(pool []*Upstream, s string) *Upstream {
var highestHash uint64
var upstream *Upstream
+ // CWE-407 fix: hash s once; combine with cached per-upstream hash using XOR.
+ // Total hash operations = 1 per request (down from N per request).
+ sHash := hash(s)
for _, up := range pool {
if !up.Available() {
continue
}
- h := hash(up.String() + s) // important to hash key and server together
+ // Combine stable upstream hash with per-request value hash.
+ // XOR preserves the avalanche property for Rendezvous hashing.
+ h := getOrCacheUpstreamHash(up) ^ sHash
if h > highestHash {
highestHash = h
upstream = up
}
}
return upstream
}