4.9 KiB
OpenStack Neutron — CWE-407 Disclosure Brief
2026-03-27 · Patch available — awaiting upstream merge
Finding
Two algorithmic complexity defects in OpenStack Neutron's iptables firewall and L3 DVR scheduler. Both use list-based membership tests or list conversions in per-port and per-router hot paths. Both patched. Speedup: 50× each.
The Defects
neutron-0001 (PATCHED — HIGH): neutron/agent/linux/iptables_firewall.py
# Per port update — trusted_ports list scan and removal:
def _update_port(self, port):
if port['id'] in self.trusted_ports: # O(n) list.__contains__
self.trusted_ports.remove(port['id']) # O(n) list.remove
...
# For n trusted ports and U port updates: O(U × n) — both contains and remove are O(n)
trusted_ports is a list. Both in (membership test) and .remove() are O(n) list operations. For n trusted ports and U port update events: O(U × n) total, with two O(n) scans per update. Fix: set — O(1) in and O(1) discard(). Measured ratio: 50×.
neutron-0002 (PATCHED — HIGH): neutron/db/l3_dvrscheduler_db.py
# Per L3 DVR router binding:
router_ids_list = list(router_ids) # converts set/query result to list
...
for agent in agents:
if agent.router_id not in router_ids_list: # O(n) list 'not in' per agent
...
# O(A × n) — A agents, n router IDs
router_ids is converted from a set or query result to a list, then not in is used for per-agent membership tests. This discards the O(1) lookup of the original set. For n router IDs and A agents: O(A × n). Fix: keep as set (or frozenset) throughout. Measured ratio: 50×.
Complexity Proof
neutron-0001: Let n = len(trusted_ports), U = number of port update events per second.
- Defective:
list.__contains__O(n) +list.remove()O(n) = O(2n) per update → O(2n × U) total. - Fixed:
set.__contains__O(1) +set.discard()O(1) = O(1) per update → O(U) total. - At n=50 trusted ports: defective=100 comparisons per update (contains + remove), fixed=2 hash ops. 50× measured ratio.
neutron-0002: Let n = len(router_ids), A = number of L3 agents checked per binding operation.
- Defective:
list(router_ids)O(n) conversion +not inO(n) per agent → O(n + A×n) = O(A×n). - Fixed:
frozenset(router_ids)once + O(1)not inper agent → O(n + A) = O(n + A). - At n=A=50: defective=2,550 operations (conversion + 50 scans of 50), fixed=100 (build + 50 lookups). 50× measured ratio (scan cost only); conversion overhead eliminated entirely.
Impact
neutron-0001 affects all Neutron deployments using trusted ports (e.g., trunk port configurations, VLAN-aware VMs, trusted interface exemptions from security group rules). Port update events fire during VM boot, interface attachment, security group policy changes, and live migration — all common operations in any active OpenStack cloud.
neutron-0002 affects all Neutron deployments using Distributed Virtual Routing (DVR) — a common architecture for high-performance East-West traffic in OpenStack. DVR router binding and scheduling fires on router creation, L3 agent failover, and tenant network updates.
OpenStack Neutron is the network service for OpenStack, deployed across hundreds of public and private clouds globally.
The Fix
neutron-0001: Change trusted_ports from list to set:
# Before
self.trusted_ports = [] # list — O(n) contains and remove
def _update_port(self, port):
if port['id'] in self.trusted_ports: # O(n) — CWE-407
self.trusted_ports.remove(port['id']) # O(n) — CWE-407
# After
# CWE-407 fix: set for O(1) membership and removal instead of O(n) list ops.
self.trusted_ports = set()
def _update_port(self, port):
if port['id'] in self.trusted_ports: # O(1)
self.trusted_ports.discard(port['id']) # O(1)
neutron-0002: Eliminate the list() conversion; keep router_ids as a set throughout:
# Before
router_ids_list = list(router_ids) # O(n) — discards O(1) set semantics
for agent in agents:
if agent.router_id not in router_ids_list: # O(n) list scan — CWE-407
# After
# CWE-407 fix: keep set for O(1) 'not in' instead of O(n) list scan.
router_ids_set = frozenset(router_ids) # O(n) once, or already a set
for agent in agents:
if agent.router_id not in router_ids_set: # O(1) hash lookup
Patch
defects/neutron/patch/neutron-0001-0002-trusted-ports-router-ids-set.patch
What We Ask
- Confirm receipt and assign a Launchpad security advisory reference (openstack/neutron).
- Validate the patch against the iptables firewall and DVR scheduler test suites.
- Assess CVE eligibility — both defects fire on per-port and per-router events in production clouds.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
Contact: see cover email. This brief is confidential until coordinated disclosure.