java-topology/whitepaper/outreach/linkerd2.md

2.6 KiB
Raw Blame History

Linkerd2 — CWE-407 Disclosure Brief

2026-03-27 · Patch available — awaiting upstream merge

Finding

One O(n²) defect in Linkerd2's federated service controller. federatedService.update() uses slices.Contains in an O(N²) diff algorithm to compute the difference between old and new remote discovery sets. Measured at 1,650×. Patch ready for upstream review.

The Defects

linkerd2-0001 (PATCHED — HIGH): controller/api/destination/server.go

// Inside federatedService.update() — per service reconciliation:
for _, remote := range newRemotes {
    if slices.Contains(oldRemotes, remote) {  // O(N) scan per new remote
        continue
    }
    // add remote
}
for _, remote := range oldRemotes {
    if slices.Contains(newRemotes, remote) {  // O(N) scan per old remote
        continue
    }
    // remove remote
}
// O(N²) total diff

slices.Contains used in O(N²) diff algorithm. Fix: remoteDiscovery map[ID]struct{}. Measured ratio: 1,650×.

Complexity Proof

For N=1,650 remote discovery entries:

  • Two-pass diff: O(N) × O(N) each = O(N²) total
  • Fixed: map[ID]struct{} for both old and new → O(N)
  • At N=1,650: 2,722,500 comparisons vs 3,300 map ops
  • 1,650× measured ratio.

Impact

All Linkerd2 deployments using multi-cluster federated services. Federated service updates fire on every service topology change — pod starts, pod stops, endpoint updates, and health status changes. Linkerd2 is a lightweight service mesh used in production Kubernetes deployments. Multi-cluster deployments with many federated service endpoints hit worst case on every endpoint change event.

The Fix

Replace the O(N²) diff with map[ID]struct{} sets:

// Before: O(N²) slices.Contains diff
for _, remote := range newRemotes {
    if slices.Contains(oldRemotes, remote) { continue }
    // add
}

// After
// CWE-407 fix: map[ID]struct{} for O(N) diff instead of O(N²) slices.Contains scan.
oldSet := make(map[RemoteID]struct{}, len(oldRemotes))
for _, r := range oldRemotes { oldSet[r.ID] = struct{}{} }

for _, remote := range newRemotes {
    if _, ok := oldSet[remote.ID]; ok { continue }
    // add
}

Patch

defects/linkerd2/patch/linkerd2-0001-federated-service-map-diff.patch

What We Ask

  1. Confirm receipt and assign a GitHub Security Advisory or issue reference.
  2. Validate the patch against your federated service and destination test suites.
  3. Assess CVE eligibility — measured at 1,650× on federated service endpoint updates.
  4. Coordinate a disclosure date — we are targeting 90 days from first contact.

Contact: see cover email. This brief is confidential until coordinated disclosure.