71 lines
2 KiB
Diff
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;
|
|
}
|