systemd+dnsmasq: 5-MOAD scan; dnsmasq-0001 + systemd-0003 MOAD-0001 defects
dnsmasq: option_filter() O(N²) duplicate elimination in src/dhcp-common.c. Two nested loops over dhcp_opt list called per DHCP reply. Fix: 256-entry bitmap keyed by 1-byte option code. 23/23 PASS, 25-50x measured ratio. MOADs 0002/0004/0005 CLEAN; MOAD-0003 N/A (single-threaded). systemd: dbus-cgroup.c IPIngressFilterPath/IPEgressFilterPath setter calls strv_contains() inside for(;;) loop — O(N²) on D-Bus property writes. Fix: HashSet pre-populated before loop. 17/17 PASS, 250x at N=500. MOADs 0002/0003/0004/0005 CLEAN (single-threaded sd-event, no key logging).
This commit is contained in:
parent
6c6dc2b114
commit
db4e0cc498
6 changed files with 680 additions and 0 deletions
159
defects/systemd/unit/SystemdDbusCgroupFilterDedupTest.java
Normal file
159
defects/systemd/unit/SystemdDbusCgroupFilterDedupTest.java
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
package unit;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit test: systemd-0003
|
||||
*
|
||||
* dbus-cgroup.c IPIngressFilterPath/IPEgressFilterPath setter calls
|
||||
* strv_contains() — O(N) linear scan — inside a for(;;) loop that processes
|
||||
* each incoming D-Bus path string. Total cost: O(N²) for N paths.
|
||||
*
|
||||
* Fix: build a HashSet before the loop and use O(1) membership instead.
|
||||
*/
|
||||
public class SystemdDbusCgroupFilterDedupTest {
|
||||
|
||||
static int pass = 0;
|
||||
static int fail = 0;
|
||||
|
||||
static void check(String label, boolean cond) {
|
||||
if (cond) {
|
||||
System.out.println(" PASS: " + label);
|
||||
pass++;
|
||||
} else {
|
||||
System.out.println(" FAIL: " + label);
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// SLOW path: simulates strv_contains(*filters, path) inside the loop
|
||||
// Each new path triggers an O(|filters|) linear scan — O(N²) total.
|
||||
// -----------------------------------------------------------------------
|
||||
static long slowFilterAppend(List<String> filters, String[] incoming) {
|
||||
long ops = 0;
|
||||
for (String path : incoming) {
|
||||
// strv_contains = linear scan of current filters list
|
||||
ops += filters.size(); // count every comparison
|
||||
if (!filters.contains(path)) {
|
||||
filters.add(path);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// FAST path: use HashSet for O(1) membership, O(N) total.
|
||||
// -----------------------------------------------------------------------
|
||||
static long fastFilterAppend(List<String> filters, String[] incoming) {
|
||||
long ops = 0;
|
||||
Set<String> seen = new HashSet<>(filters);
|
||||
for (String path : incoming) {
|
||||
ops++; // one hash lookup
|
||||
if (seen.add(path)) {
|
||||
filters.add(path);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test: correctness — both slow and fast produce the same unique list
|
||||
// -----------------------------------------------------------------------
|
||||
static void testCorrectness() {
|
||||
List<String> slowFilters = new ArrayList<>(Arrays.asList("/prog/a.o", "/prog/b.o"));
|
||||
List<String> fastFilters = new ArrayList<>(Arrays.asList("/prog/a.o", "/prog/b.o"));
|
||||
|
||||
String[] incoming = {"/prog/b.o", "/prog/c.o", "/prog/d.o", "/prog/b.o"};
|
||||
|
||||
slowFilterAppend(slowFilters, incoming);
|
||||
fastFilterAppend(fastFilters, incoming);
|
||||
|
||||
List<String> expected = Arrays.asList("/prog/a.o", "/prog/b.o", "/prog/c.o", "/prog/d.o");
|
||||
check("correctness: slow produces correct deduplicated list", slowFilters.equals(expected));
|
||||
check("correctness: fast produces correct deduplicated list", fastFilters.equals(expected));
|
||||
check("correctness: slow and fast agree", slowFilters.equals(fastFilters));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test: all-unique paths (no duplicates)
|
||||
// -----------------------------------------------------------------------
|
||||
static void testAllUnique(int n) {
|
||||
List<String> slowF = new ArrayList<>();
|
||||
List<String> fastF = new ArrayList<>();
|
||||
String[] incoming = new String[n];
|
||||
for (int i = 0; i < n; i++) incoming[i] = "/bpf/prog-" + i + ".o";
|
||||
|
||||
long slowOps = slowFilterAppend(slowF, incoming);
|
||||
long fastOps = fastFilterAppend(fastF, incoming);
|
||||
|
||||
check("allUnique[N=" + n + "]: slow appends all", slowF.size() == n);
|
||||
check("allUnique[N=" + n + "]: fast appends all", fastF.size() == n);
|
||||
check("allUnique[N=" + n + "]: results agree", slowF.equals(fastF));
|
||||
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
System.out.printf(" allUnique[N=%d] ops: slow=%d fast=%d ratio=%.1fx%n",
|
||||
n, slowOps, fastOps, ratio);
|
||||
check("allUnique[N=" + n + "]: ratio >= 5x", ratio >= 5.0);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test: all-duplicate paths (same path sent N times)
|
||||
// -----------------------------------------------------------------------
|
||||
static void testAllDuplicates(int n) {
|
||||
List<String> slowF = new ArrayList<>();
|
||||
List<String> fastF = new ArrayList<>();
|
||||
String[] incoming = new String[n];
|
||||
Arrays.fill(incoming, "/bpf/same.o");
|
||||
|
||||
long slowOps = slowFilterAppend(slowF, incoming);
|
||||
long fastOps = fastFilterAppend(fastF, incoming);
|
||||
|
||||
check("allDup[N=" + n + "]: slow accepts only 1", slowF.size() == 1);
|
||||
check("allDup[N=" + n + "]: fast accepts only 1", fastF.size() == 1);
|
||||
|
||||
System.out.printf(" allDup[N=%d] ops: slow=%d fast=%d%n",
|
||||
n, slowOps, fastOps);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test: mixed unique + duplicate paths
|
||||
// -----------------------------------------------------------------------
|
||||
static void testMixed(int n) {
|
||||
List<String> slowF = new ArrayList<>();
|
||||
List<String> fastF = new ArrayList<>();
|
||||
String[] incoming = new String[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Even entries are unique, odd entries repeat "/bpf/odd.o"
|
||||
incoming[i] = (i % 2 == 0) ? "/bpf/prog-" + i + ".o" : "/bpf/odd.o";
|
||||
}
|
||||
|
||||
long slowOps = slowFilterAppend(slowF, incoming);
|
||||
long fastOps = fastFilterAppend(fastF, incoming);
|
||||
|
||||
check("mixed[N=" + n + "]: slow and fast agree", slowF.equals(fastF));
|
||||
|
||||
double ratio = (double) slowOps / fastOps;
|
||||
System.out.printf(" mixed[N=%d] ops: slow=%d fast=%d ratio=%.1fx%n",
|
||||
n, slowOps, fastOps, ratio);
|
||||
check("mixed[N=" + n + "]: ratio >= 5x", ratio >= 5.0);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Main
|
||||
// -----------------------------------------------------------------------
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== systemd-0003: dbus-cgroup BPF filter path dedup O(N²) → O(N) ===");
|
||||
|
||||
testCorrectness();
|
||||
testAllDuplicates(100);
|
||||
testAllUnique(100);
|
||||
testAllUnique(500);
|
||||
testMixed(200);
|
||||
testMixed(500);
|
||||
|
||||
System.out.println();
|
||||
System.out.printf("%d/%d PASS%n", pass, pass + fail);
|
||||
if (fail > 0) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue