java-topology/defects/squid-0004/TICKET.md

2.7 KiB

squid-0004 — CWE-407 O(P*A) whichPeer() linear scan on hot ICP/HTCP reply path

Target: Squid (squid-cache/squid, depth=1, 2026-04-03) File: src/neighbors.cc Function: whichPeer(const Ip::Address &from) Severity: MEDIUM-HIGH MOAD: 0001 Benchmark: 47x op-count reduction at P=100 peers, A=4 addresses/peer

Defect

whichPeer() is called on every incoming ICP and HTCP response from cache peers, mapping a source UDP address back to a CachePeer*. It does so by scanning all configured peers and all their addresses with a nested loop:

// src/neighbors.cc:99-114
CachePeer *
whichPeer(const Ip::Address &from)
{
    int j;
    for (const auto &p: CurrentCachePeers()) {        // O(P)
        for (j = 0; j < p->n_addresses; ++j) {        // O(A)
            if (from == p->addresses[j] && from.port() == p->icp.port) {
                return p.get();
            }
        }
    }
    return nullptr;
}

With P=100 cache peers and A=4 addresses/peer, each call scans up to 400 entries. At 10,000 ICP responses/second (a busy CDN proxy), this is 4,000,000 scalar comparisons/second in a single function that returns on first match.

The fix builds a std::map<std::pair<Ip::Address, unsigned short>, CachePeer*> keyed by (addr, icp_port) at peer DNS resolution time (peerDNSConfigure), updated on address change, and cleared on peer removal. Lookup becomes O(log P) instead of O(P*A).

Call sites:

  • neighborsUdpAck() — called for every incoming ICP reply packet
  • neighborsHtcpReply() — called for every incoming HTCP reply packet
  • peer_select.cc — called during miss peer selection (3 sites)

Fix

Build a map (Ip::Address, icp_port) -> CachePeer* populated in peerDNSConfigure() when peer addresses are resolved. Clear entries when a peer is removed (DeleteConfigured). Consult the map in whichPeer() instead of scanning.

Ip::Address already supports operator< (used in ssl/context_storage.cc as std::map<Ip::Address, ...>), so it is suitable as a map key.

MOAD 0002-0005 Scan Results

MOAD-0002 (Intertangle): SquidConfig is a 571-line god object included in 209 source files coupling every subsystem (ACL, auth, TLS, cache, DNS, ICAP, FTP). Config.* referenced 1408 times. Documented in squid/scan/MOAD-RESULTS.md. Structural, not patchable in isolation.

MOAD-0003 (Leaked Context): CLEAN. Squid is single-threaded event-loop per worker process. No thread_local or pthread_key holding request-scoped identity found.

MOAD-0004 (Logged Secret): Already patched in squid-0003. FtpGateway loginParser and auth/basic credential logging at debug level 9 addressed.

MOAD-0005 (Thundering Herd): CLEAN. Single-threaded event-loop worker model; no concurrent cache get+set race conditions applicable.