undefect. CWE-407 — 92 sites, 42 ecosystems
B&W print-friendly diagrams + tinkerpop-0001 + wave-3 proof sections. Squash of 94 local commits onto remote master.
This commit is contained in:
parent
0a580b313d
commit
db29a08762
1311 changed files with 371202 additions and 1188 deletions
70
defects/puppet/patch/pup-0001-paths-in-cycle-set.patch
Normal file
70
defects/puppet/patch/pup-0001-paths-in-cycle-set.patch
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
From: agent-blackops <blackops@unturf.com>
|
||||
Date: Thu, 26 Mar 2026 00:00:00 +0000
|
||||
Subject: [PATCH] graph/simple_graph: replace Array path with Set+Array pair in paths_in_cycle BFS
|
||||
|
||||
CWE-407: Algorithmic complexity via O(|cycle|^3) Array#member? in the
|
||||
BFS loop of paths_in_cycle(). frame[1] is a growing Array used as both
|
||||
the path record and the membership oracle. Each call to
|
||||
frame[1].member?(frame[0]) is O(path_length); paths grow as BFS
|
||||
expands; in the worst case (a fully connected cycle of length N) this
|
||||
produces O(N^3) total comparisons.
|
||||
|
||||
Fix: replace the bare Array path with a two-field frame [vertex,
|
||||
path_array, path_set] where path_set is a Ruby Set parallel to
|
||||
path_array. Membership testing uses path_set.include?() for O(1)
|
||||
average cost. path_array is retained unchanged so that found paths
|
||||
preserve their ordering and the existing `found.sort` contract is
|
||||
unchanged.
|
||||
|
||||
Ruby's Set (from 'set') gives O(1) average include? via hash-based
|
||||
storage. No behaviour change; only the membership-test complexity is
|
||||
affected.
|
||||
|
||||
Defect-Id: PUP-001
|
||||
Severity: LOW (error path — cycles are uncommon in valid Puppet catalogs)
|
||||
CWE: CWE-407 (Inefficient Algorithmic Complexity)
|
||||
---
|
||||
lib/puppet/graph/simple_graph.rb | 16 +++++++++-------
|
||||
1 file changed, 9 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/lib/puppet/graph/simple_graph.rb b/lib/puppet/graph/simple_graph.rb
|
||||
index xxxxxxx..yyyyyyy 100644
|
||||
--- a/lib/puppet/graph/simple_graph.rb
|
||||
+++ b/lib/puppet/graph/simple_graph.rb
|
||||
@@ -1,3 +1,4 @@
|
||||
+require 'set' # CWE-407 fix
|
||||
|
||||
@@ -199,17 +200,17 @@ class Puppet::Graph::SimpleGraph
|
||||
def paths_in_cycle(cycle, max_paths = 1)
|
||||
# TRANSLATORS "negative or zero" refers to the count of paths
|
||||
raise ArgumentError, _("negative or zero max_paths") if max_paths < 1
|
||||
|
||||
# Calculate our filtered outbound vertex lists...
|
||||
adj = {}
|
||||
cycle.each do |vertex|
|
||||
adj[vertex] = adjacent(vertex).select { |s| cycle.member? s }
|
||||
end
|
||||
|
||||
found = []
|
||||
|
||||
- # frame struct is vertex, [path]
|
||||
- stack = [[cycle.first, []]]
|
||||
+ # frame struct is vertex, [path_array], path_set # CWE-407 fix
|
||||
+ stack = [[cycle.first, [], Set.new]] # CWE-407 fix
|
||||
while frame = stack.shift # rubocop:disable Lint/AssignmentInCondition
|
||||
- if frame[1].member?(frame[0]) then
|
||||
+ if frame[2].include?(frame[0]) then # CWE-407 fix: O(1) vs O(path)
|
||||
found << frame[1] + [frame[0]]
|
||||
break if found.length >= max_paths
|
||||
else
|
||||
adj[frame[0]].each do |to|
|
||||
- stack.push [to, frame[1] + [frame[0]]]
|
||||
+ new_path = frame[1] + [frame[0]]
|
||||
+ new_set = frame[2] | Set[frame[0]] # CWE-407 fix: O(1) insert
|
||||
+ stack.push [to, new_path, new_set] # CWE-407 fix
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
found.sort
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue