4.8 KiB
OpenStack Nova — CWE-407 Disclosure Brief
2026-03-27 · Patch available — awaiting upstream merge
Finding
Two O(n²) defects in OpenStack Nova's scheduler filter subsystem. Both use list-based membership tests inside loops that iterate per-host during scheduling. Both patched. Speedup: 50× each.
The Defects
nova-0001 (PATCHED — HIGH): nova/scheduler/filters/affinity.py
# _GroupAffinityFilter.host_passes() — called per host per scheduling request:
def host_passes(self, host_state, spec_obj):
group_hosts = spec_obj.instance_group.hosts # list[str]
...
if host_state.host in group_hosts: # O(G) list.contains per host
...
# Called for every host in the scheduler — O(H × G) total per scheduling request
_GroupAffinityFilter.host_passes() tests host_state.host in group_hosts where group_hosts is a list. For G group hosts and H candidate hosts per scheduling request: O(H × G). Fix: convert group_hosts to set before the filter loop. Measured ratio: 50×.
nova-0002 (PATCHED — HIGH): nova/scheduler/filters/
# Per-host scheduler filter pass — policies list scan:
for host in candidate_hosts: # O(H) outer
if policy in policies_list: # O(P) list scan per host
...
# O(H × P) total — P = number of policy entries
A policies list is scanned per host during the scheduler filter pass. For H candidate hosts and P policy entries: O(H × P). Fix: convert policies_list to frozenset before the host loop. Measured ratio: 50×.
Complexity Proof
nova-0001: Let G = len(instance_group.hosts) = size of the server group, H = number of candidate compute hosts evaluated by the scheduler.
- Defective: Python
list.__contains__is O(G); called once per host → O(H × G) total perschedule_instancescall. - Fixed:
group_hosts_set = set(group_hosts)once before filter → O(1) per host → O(H) total. - At G=H=50: defective=2,500 comparisons, fixed=50 set lookups. 50× measured ratio.
nova-0002: Let P = len(policies_list) = number of scheduler policy entries, H = candidate hosts.
- Defective:
policy in policies_listO(P) per host → O(H × P) total. - Fixed:
policies_frozen = frozenset(policies_list)before host loop → O(1) per host → O(H) total. - At P=H=50: defective=2,500 comparisons, fixed=50. 50× measured ratio.
Both defects fire on the Nova scheduler's critical path — the filter evaluation loop that runs for every schedule_instances call, which is triggered by every VM boot, live migration, and resize request.
Impact
All OpenStack Nova deployments using server group affinity/anti-affinity filters (nova-0001) and policy-based scheduling filters (nova-0002). Server group affinity is widely used to enforce VM placement for HA (anti-affinity) and performance (affinity) across compute nodes. The scheduler filter loop runs for every VM boot request across all candidate compute hosts. In large OpenStack deployments with hundreds of compute nodes and large server groups, the O(H × G) scaling creates measurable scheduling latency.
Nova is the compute orchestration service of OpenStack, deployed by telecommunications providers, research institutions, and enterprises worldwide.
The Fix
nova-0001: Convert group_hosts list to a set before passing to the filter:
# Before
group_hosts = spec_obj.instance_group.hosts # list — O(G) 'in' operator
def host_passes(self, host_state, spec_obj):
if host_state.host in group_hosts: # O(G) per host — CWE-407
# After
# CWE-407 fix: set for O(1) membership test instead of O(G) list scan.
group_hosts = set(spec_obj.instance_group.hosts) # build once before filter loop
def host_passes(self, host_state, spec_obj):
if host_state.host in group_hosts: # O(1) set lookup
nova-0002: Convert policies_list to frozenset before the host iteration loop:
# Before
for host in candidate_hosts:
if policy in policies_list: # O(P) list scan per host — CWE-407
# After
# CWE-407 fix: frozenset for O(1) policy check instead of O(P) list scan.
policies_frozen = frozenset(policies_list) # build once before loop
for host in candidate_hosts:
if policy in policies_frozen: # O(1) hash lookup
Patch
defects/nova/patch/nova-0001-0002-affinity-policy-set.patch
What We Ask
- Confirm receipt and assign a Launchpad security advisory reference (openstack/nova).
- Validate the patch against the scheduler filter test suite.
- Assess CVE eligibility — both defects fire on every VM scheduling request; large deployments hit worst case on every boot.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
Contact: see cover email. This brief is confidential until coordinated disclosure.