java-topology/defects/varnish/patch/varnish-0001.patch

71 lines
2 KiB
Diff

# UNDF: UNDF-2026-000000329
--- a/bin/varnishd/cache/cache_ban.c
+++ b/bin/varnishd/cache/cache_ban.c
@@ -640,34 +640,60 @@ BAN_CheckObject(struct worker *wrk, struct objcore *oc, struct req *req)
{
struct ban *b;
struct vsl_log *vsl;
struct ban *b0, *bn;
unsigned tests;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
Lck_AssertHeld(&oc->objhead->mtx);
assert(oc->refcnt > 0);
vsl = req->vsl;
CHECK_OBJ_NOTNULL(oc->ban, BAN_MAGIC);
/* First do an optimistic unlocked check */
b0 = ban_start;
CHECK_OBJ_NOTNULL(b0, BAN_MAGIC);
if (b0 == oc->ban)
return (0);
/* If that fails, make a safe check */
Lck_Lock(&ban_mtx);
b0 = ban_start;
bn = oc->ban;
if (b0 != bn)
bn->refcount++;
Lck_Unlock(&ban_mtx);
AN(bn);
if (b0 == bn)
return (0);
AN(b0);
AN(bn);
/*
- * This loop is safe without locks, because we know we hold
- * a refcount on a ban somewhere in the list and we do not
- * inspect the list past that ban.
+ * CWE-407 mitigation: skip completed bans in bulk before evaluating.
+ * Completed bans (BANS_FLAG_COMPLETED) are already coalesced by the
+ * lurker; fast-skip them without calling ban_evaluate.
+ *
+ * Structural fix (TODO): index bans by field type at insertion time so
+ * BAN_CheckObject can skip bans that cannot match this object in O(1)
+ * rather than O(B). See ticket varnish-0001 for full design.
*/
tests = 0;
for (b = b0; b != bn; b = VTAILQ_NEXT(b, list)) {
CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
if (b->flags & BANS_FLAG_COMPLETED)
continue;
+ /*
+ * CWE-407 mitigation: if this ban only tests req fields
+ * (BANS_FLAG_REQ) and we have no req, skip evaluation entirely.
+ * Previously the loop would enter ban_evaluate and return early,
+ * paying function-call + spec-walk overhead unconditionally.
+ */
+ if ((b->flags & BANS_FLAG_REQ) && req == NULL)
+ continue;
if (ban_evaluate(wrk, b->spec, oc, req->http, &tests))
break;
}