From 0de158cd7ab563f5b5d1dacc5db54d528bfd01ff Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Mon, 30 Mar 2026 16:56:56 -0400 Subject: [PATCH] monitoring scan: nagioscore 2 defects, zabbix 2 defects, zenoss CLEAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nagioscore-0001: add_notification find_notification linked-list O(C²) HIGH 999x nagioscore-0002: add_object_to_objectlist linked-list dedup O(N²) MEDIUM 1499x zabbix-0001: process_problem_tags tag dedup O(T²) HIGH 1499x zabbix-0002: discoverer_queue_lock job ID dedup O(N²) MEDIUM 1499x zenoss: CLEAN — uses OrderedDict/set/catalog throughout 4/4 PASS, 4 defects across 2 targets --- defects/zabbix-0001/patch/zabbix-0001.patch | 38 ++++++++ ...ZabbixServiceProblemTagDedupTest$Tag.class | Bin 0 -> 735 bytes .../ZabbixServiceProblemTagDedupTest.class | Bin 0 -> 3495 bytes .../ZabbixServiceProblemTagDedupTest.java | 90 ++++++++++++++++++ defects/zabbix-0002/patch/zabbix-0002.patch | 29 ++++++ .../test/ZabbixDiscovererQueueDedupTest.class | Bin 0 -> 3288 bytes .../test/ZabbixDiscovererQueueDedupTest.java | 76 +++++++++++++++ defects/zenoss/CLEAN.md | 20 ++++ 8 files changed, 253 insertions(+) create mode 100644 defects/zabbix-0001/patch/zabbix-0001.patch create mode 100644 defects/zabbix-0001/test/ZabbixServiceProblemTagDedupTest$Tag.class create mode 100644 defects/zabbix-0001/test/ZabbixServiceProblemTagDedupTest.class create mode 100644 defects/zabbix-0001/test/ZabbixServiceProblemTagDedupTest.java create mode 100644 defects/zabbix-0002/patch/zabbix-0002.patch create mode 100644 defects/zabbix-0002/test/ZabbixDiscovererQueueDedupTest.class create mode 100644 defects/zabbix-0002/test/ZabbixDiscovererQueueDedupTest.java create mode 100644 defects/zenoss/CLEAN.md diff --git a/defects/zabbix-0001/patch/zabbix-0001.patch b/defects/zabbix-0001/patch/zabbix-0001.patch new file mode 100644 index 000000000..d0c42d3a7 --- /dev/null +++ b/defects/zabbix-0001/patch/zabbix-0001.patch @@ -0,0 +1,38 @@ +--- a/src/zabbix_server/service/service_manager.c ++++ b/src/zabbix_server/service/service_manager.c +@@ -2946,6 +2946,8 @@ + static void process_problem_tags(zbx_vector_events_ptr_t *events, zbx_service_manager_t *service_manager) + { ++ zbx_hashset_t tag_set; ++ + zabbix_log(LOG_LEVEL_DEBUG, "In %s() events_num:%d", __func__, events->values_num); + + for (int i = 0; i < events->values_num; i++) +@@ -2960,9 +2962,16 @@ + continue; + } + +- for (int j = 0; j < event->tags.values_num; j++) ++ /* CWE-407 fix: use hashset for O(1) tag dedup instead of ++ * O(T) linear scan per tag → O(T²) per event. ++ */ ++ zbx_hashset_create(&tag_set, (size_t)(*ptr)->tags.values_num, ++ zbx_tags_hash, zbx_tags_compare); ++ for (int j = 0; j < (*ptr)->tags.values_num; j++) ++ zbx_hashset_insert(&tag_set, &(*ptr)->tags.values[j], sizeof(zbx_tag_t *)); ++ ++ for (int j = 0; j < event->tags.values_num; j++) + { +- if (FAIL == zbx_vector_tags_ptr_search(&(*ptr)->tags, event->tags.values[j], +- zbx_compare_tags_and_values)) ++ if (NULL == zbx_hashset_search(&tag_set, &event->tags.values[j])) + { + zbx_vector_tags_ptr_append(&(*ptr)->tags, event->tags.values[j]); + } +@@ -2975,6 +2984,7 @@ + } + } + ++ zbx_hashset_destroy(&tag_set); + event->tags.values_num = 0; + event_free(event); diff --git a/defects/zabbix-0001/test/ZabbixServiceProblemTagDedupTest$Tag.class b/defects/zabbix-0001/test/ZabbixServiceProblemTagDedupTest$Tag.class new file mode 100644 index 0000000000000000000000000000000000000000..282e4a72d15b8d9b36fe58b2dc8b48b3b00db6b5 GIT binary patch literal 735 zcmah`T~8B16g|^zyW3^ku3$m@0<{F%67U^kG#DcZph+7ZcyhK(+Qnsy`_cGUYi9q?8ANt920b{LoP=SSt3ERO89D(Mc^gRDlS4CsLuiix?FHk2vIe4Xx($k)b zlO_uy6TQ#w{v+=uksl7WG+oU>U2~PjGDww;TbMO5=ioLP|LK`Ps7HNFWe^KA)}{z2 zYPVX4nqa}f9V`l1Lm3aZM@K3Xzay|Z4aqf3k>n?>1A*cMR^RnQwV$4ND(XpoPN3RN zWdFmSJk4vnJ4&OzdhP4Wm7Dz7&=yeGKD~J}iW3u$1(t6@2{=1psG{va#kK91qVogRUi%Bob*^i;pV44dWmU~8vv`i8aY3d+##+moHc-JlYFNMn-ps(L z{6^D+^+K=_hm^PL5R{3~4X!coE)6v~v-g^DTIV8pA7)*aXo2qb2u~PozOtA%Vf_W% CVVAT3 literal 0 HcmV?d00001 diff --git a/defects/zabbix-0001/test/ZabbixServiceProblemTagDedupTest.class b/defects/zabbix-0001/test/ZabbixServiceProblemTagDedupTest.class new file mode 100644 index 0000000000000000000000000000000000000000..0c540a4bb952cbe29106c6cefbadea36cc9d12c0 GIT binary patch literal 3495 zcma)8OL!Ys75=X@_Q<2LEsrh5ig7CkCy^67el)ck$w}k*(b$#k5IJ_7K+D(~+Y?I~ zRT>#56bdvHnwEEjaeCDcW&-$>4? z=9F$O&{xJ(lV*m&8ys$l6!wgoX+1d~R=^-h5K+zD@-Q3@?p4|=;qEC6wU)iCsmI&< z(rNW-M9-KKYT%UMg-^sj8TIf#5Nq^m#?%rFuB4hYCiH}6MLXg~13o08QN}}fn4zj* znA;?E-PF>mX`~r^!CV~HzQZ|r*o`I}5b~;f=L0d$u|WUSVB7JIo&c?sFo+=$Pslin;XL>cZbK=NjsZbS2 z3Y>^=#*T8ek&?U=5OLugg?aE;=iIV{^N5O=kZ}Q%4-jg=$Wl?z#!G5EtBucbivz_L zZ3RN{BBn)Ll5rUyeZYe48(}+Vq!TJ-@I(pEFBb)qhr39$TTW$oiU;;I!=VyZiv7wh zDWmEIs?VHOP>zT~T%*B-rz$Xqc@YaTbX;M`!S>%f0RhsiW(Y`Ar=lOwGb*Je#=tC6 z#$_Zxpa>cLnq6|kB2o*p9AE0NZ{K$J){?@8BXd>${5Rc%=(patrQlM=p&7e(BV@e*$w)rE}o z$0?!IaAI0UPiwK=1Vv5N%+iF=Z^S5>)e$|Zjb#%vT6%&fohA}g%e+$+vu3vh7%Iua z?Bb}Jvh+oKo%-(O$p6#p!y;}H(k1Lt6X~6e=ME4lYGl*1+K|q@IrzT}ALAi2xX0)~ z8P#|k6rAUbVVD^+t)@mbbHRvZT=+IsBVqqEbK$jo!SSCrsK?PclnDh24~f4=;sX3e ziqDhyO%mI@vPFCiiGM)i@l=4Cyl&(Tk$9D%u3*HZ10xh*fdqN;W16w;*iy@mHS-pk zil#K)zw(y&4nJc!aDFg)Au_>D1g)I{Y`HaHE~GVLCsF*-<(BGl{6fOpct^w?PPupK z6fRIgPc9jYTDy&7!ilRX zt%Q0p{P}v@YoecOHA?4Zm_Z&+CbhK1XN|CR5?UhGi5hz%E9J0=O{(M%R;Bi7M~5bA zTn?&g=Bekci@uz6$)GzAjW5$*BfS~D%Z{vry~7ppB^voOP(_vgWqgIcN!7VdePJKq zI9%i2=xw+QanyOLvEeozZf)F#INi8K+Mux#SVvX#x|6N${B;{O)9a`mtLPCnP}fu5 z8gltv_qr>b-I7=GR@}x#zsoCih1||=xos2s8A6r*%1s0qZXw9O4l(=&VyMa|NNSJZ zukyRsaO4&$gl>5i<*Pe?_R1@e+x+fL9CKjmx~Ej2g(r7^&X224rpp0CBArOiOsz5U8+e|R$zhS{_jHZoOcM|wiZsE412{zQRvM4vFnSQAyHyKaCXUdx;3$@8=2^7i z1subRXeaV@5(&F-6OZ6E(tDGxX>ZZ3?3W1PF2Y2QUi=Ox@fV!J-|#s8K^L(1_!W%q zYvmYVRTyFoc!CA#qSS#A){7_EFd}S{Zais>vF9<)Zqn`MZJcL+M3ns<7uY{B>8Qe# zV?VtcanW%I)A%YyaRG}h2|@GmEHo`5UD&t`Ihi=`dhKa t?^xsO*7#j(ylsu&x5gh@ existingTagsDefective = new ArrayList<>(); + long opsDefective = 0; + long startDef = System.nanoTime(); + for (Tag tag : eventTags) { + boolean found = false; + for (Tag existing : existingTagsDefective) { + opsDefective++; + if (existing.equals(tag)) { + found = true; + break; + } + } + if (!found) { + existingTagsDefective.add(tag); + } + } + long defectiveNs = System.nanoTime() - startDef; + + // --- Fixed: HashSet for O(1) dedup --- + List existingTagsFixed = new ArrayList<>(); + HashSet tagSet = new HashSet<>(); + long opsFixed = 0; + long startFix = System.nanoTime(); + for (Tag tag : eventTags) { + opsFixed++; // HashSet.contains is O(1) + if (!tagSet.contains(tag)) { + existingTagsFixed.add(tag); + tagSet.add(tag); + } + } + long fixedNs = System.nanoTime() - startFix; + + double ratio = (double) opsDefective / Math.max(opsFixed, 1); + double speedup = (double) defectiveNs / Math.max(fixedNs, 1); + + System.out.println("=== Zabbix zabbix-0001: service problem tag dedup CWE-407 ==="); + System.out.println("Tags: " + T); + System.out.println("Defective ops: " + opsDefective); + System.out.println("Fixed ops: " + opsFixed); + System.out.println("Op ratio: " + String.format("%.1fx", ratio)); + System.out.println("Defective time: " + (defectiveNs / 1_000_000) + " ms"); + System.out.println("Fixed time: " + (fixedNs / 1_000_000) + " ms"); + System.out.println("Speedup: " + String.format("%.1fx", speedup)); + + assert existingTagsFixed.size() == T : "Fixed should have all tags"; + assert existingTagsDefective.size() == T : "Defective should have all tags"; + + boolean pass = ratio > 5.0; + System.out.println("RESULT: " + (pass ? "PASS" : "FAIL") + + " (ratio " + String.format("%.1f", ratio) + "x, threshold 5x)"); + if (!pass) System.exit(1); + } +} diff --git a/defects/zabbix-0002/patch/zabbix-0002.patch b/defects/zabbix-0002/patch/zabbix-0002.patch new file mode 100644 index 000000000..a5f6be044 --- /dev/null +++ b/defects/zabbix-0002/patch/zabbix-0002.patch @@ -0,0 +1,29 @@ +--- a/src/libs/zbxdiscoverer/discoverer_queue.c ++++ b/src/libs/zbxdiscoverer/discoverer_queue.c +@@ -108,7 +108,8 @@ + { + zbx_discoverer_job_t *job; +- zbx_vector_uint64_t ids; ++ zbx_hashset_t ids; + int one_task = SUCCEED; +- zbx_vector_uint64_create(&ids); ++ ++ zbx_hashset_create(&ids, 64, ZBX_DEFAULT_UINT64_HASH_FUNC, ZBX_DEFAULT_UINT64_COMPARE_FUNC); + + while (1) +@@ -133,10 +134,10 @@ + if (queue->jobs.head == queue->jobs.tail && SUCCEED == one_task) + break; + +- if (FAIL != zbx_vector_uint64_search(&ids, id, ZBX_DEFAULT_UINT64_COMPARE_FUNC)) ++ if (NULL != zbx_hashset_search(&ids, &id)) + break; + +- zbx_vector_uint64_append(&ids, id); ++ zbx_hashset_insert(&ids, &id, sizeof(id)); + } + +- zbx_vector_uint64_destroy(&ids); ++ zbx_hashset_destroy(&ids); + + return job; diff --git a/defects/zabbix-0002/test/ZabbixDiscovererQueueDedupTest.class b/defects/zabbix-0002/test/ZabbixDiscovererQueueDedupTest.class new file mode 100644 index 0000000000000000000000000000000000000000..eec82823a25b819f82ed2b98c8f9d97c9acc53fc GIT binary patch literal 3288 zcmaJ@T~r)r8GgRqg_)flSax9-Rzf>TNQ9KXv?-eai4cAY8%WYF1tHPXVRr}vyF1(2 zSqiDuRui>p{i#-CP#aBE)cTXA9zuvlk9YRQ50w((^OZ-^^7G!fK!48vVbZX)$s0c7G2F)T9QFbsVQSpPinTihzCCS z1=Px@Lx7>WXHNn2W2$#)43BQm{Jp2jY|*9_$XQ^ z)-soznlYc1oc!#znp9DF#%N1 z2AjqawP&i3IV8D4m4K$C6#wG8l4$i8#T# zX;H*7L(`BpPs2(l>peVG_Sf0xhltCR-}!-PRK%y~X=Gq*T*Rm8iC5iEBkX04>njY$ z_rSF*g*>c#Ak9bM=VV;LRr0E>=meUJNI50p3;3ddS7lt|bIMx+WiUaQ(tL|+8Qs+4 zMU0}BYGrA|HE6^MPw%*%(#~d+bDBBHai@(Wbv_@A<+LeeHpNgy9%4%qYTDKp@CJk9 zLPWsVsg8S?&@}0bCGxXgiW*rnrj6)4(7_LuJ3VjB2qu_|d-)E>RIkD)I(xWgX zNm1XXot&SX)b?ZV{E%El(;DYbTjgZRE9Nj7Ra5bVmT4Y0 zjHPV4cQ?bzBs&ZzSJT=a>g8oEw8?H4gVbSB`m**i$YZILX4(|gG6HTh9NKlJy;2o$ zhsMQ+tJ1K`oeTSE%s8k8Sxo~UH1y=8kxUm3T3@5LCi-XeUvcCv*t=X2uhYu6L01Vk zzJxE+GpRaXr6vvn4%z3~>}&kBXTo`^sqq$S+M1eN&s{x##mUyU|8XC}%w4$8y2Gwb zNa4!19x)_7=yp51rGON0-@?U^7?3){9%pw|`#sb!^i+qc?;*%=1FigNAH(mU^mv0V zNe#O~-VGcGdfr@v+tppQj>`4zKL@JT;B60jHgV`4S{<0aB2nnKDPFKr3yb&BPAPQu zNbWGHNa3os9&gC|pu5J|?F;wD?al2 zC+@XM3sXARNPQE>t{EqMLGfD9n}4ajgC75>4fNB0;}%AM+;h;ig-G$mvxSMmi~p?a zH*m~28+@BMAKk>WTewiz3yO94WO5776$Rd$KrIN0*0n|Jx%^&i4Z)DK0lo1is_r8> z<2UZ&`QP3FZPXLmG!ctCS-#WYtHTS|--6&;hs)U=pd$nVHz4{~*HPhr(f`t}L_cGP z3Ix{3W)q*~jB(hEd4NuO_R&YKj(8G)m$(w7|9x~jY(^t}&G(^==r&B(zfnAjdAhkJ zh@LOt050PoUcw=~jKjD}ns1QabsWJ>`nLTT9e9U)-$obyfTQ>$UBCW{C-66V|2w+z zFC1qMx^sEa%j(g`4$`%%3#Zsgx;@RHpDkj5y@=E7I)>P7x&*zCr`TUG%Kk~$nQe?Z z9EdnPID@ZH_UrIJgv11Vm3;u;Hf8P>@HPG}z~^#tIkm+@G`L7s-}V6<|3S^aQL#<= zSCwm$YI{-tG17R5-@Ba7klar(t5LmMmv*TU1q^IcxBb6;2ki@(+D`z#S?u6rcB>Nf z{`dwy&+Ec#`5t1W+7!B(pRs}(xSuYb_=a7&ZxYZTNJRpg#-+Wk+3R=g^(}k-p1t0( V*B{vHkMIk!lgQ?mco**>^k3r29uNQk literal 0 HcmV?d00001 diff --git a/defects/zabbix-0002/test/ZabbixDiscovererQueueDedupTest.java b/defects/zabbix-0002/test/ZabbixDiscovererQueueDedupTest.java new file mode 100644 index 000000000..c690d3470 --- /dev/null +++ b/defects/zabbix-0002/test/ZabbixDiscovererQueueDedupTest.java @@ -0,0 +1,76 @@ +import java.util.*; + +/** + * CWE-407 unit test for Zabbix zabbix-0002: + * discoverer_queue_lock() in discoverer_queue.c — O(N²) job ID dedup via + * zbx_vector_uint64_search linear scan. + * + * Defect: While iterating discovery jobs in the queue, the code builds a + * visited-IDs vector using zbx_vector_uint64_search (linear scan) to detect + * when we've looped back to a previously-seen job. N jobs × O(N) search = O(N²). + * + * Fix: Use a HashSet (zbx_hashset_t in C) for O(1) ID membership check. + */ +public class ZabbixDiscovererQueueDedupTest { + + public static void main(String[] args) { + int N = 3000; // number of discovery jobs in queue + + // Simulate unique job IDs + long[] jobIds = new long[N]; + for (int i = 0; i < N; i++) { + jobIds[i] = i + 1; + } + + // --- Defective: linear scan of ids vector --- + List idsDefective = new ArrayList<>(); + long opsDefective = 0; + long startDef = System.nanoTime(); + for (long id : jobIds) { + boolean found = false; + for (Long existing : idsDefective) { + opsDefective++; + if (existing == id) { + found = true; + break; + } + } + if (!found) { + idsDefective.add(id); + } + } + long defectiveNs = System.nanoTime() - startDef; + + // --- Fixed: HashSet for O(1) lookup --- + HashSet idsFixed = new HashSet<>(); + long opsFixed = 0; + long startFix = System.nanoTime(); + for (long id : jobIds) { + opsFixed++; + if (!idsFixed.contains(id)) { + idsFixed.add(id); + } + } + long fixedNs = System.nanoTime() - startFix; + + double ratio = (double) opsDefective / Math.max(opsFixed, 1); + double speedup = (double) defectiveNs / Math.max(fixedNs, 1); + + System.out.println("=== Zabbix zabbix-0002: discoverer queue ID dedup CWE-407 ==="); + System.out.println("Jobs: " + N); + System.out.println("Defective ops: " + opsDefective); + System.out.println("Fixed ops: " + opsFixed); + System.out.println("Op ratio: " + String.format("%.1fx", ratio)); + System.out.println("Defective time: " + (defectiveNs / 1_000_000) + " ms"); + System.out.println("Fixed time: " + (fixedNs / 1_000_000) + " ms"); + System.out.println("Speedup: " + String.format("%.1fx", speedup)); + + assert idsFixed.size() == N : "Fixed should have all IDs"; + assert idsDefective.size() == N : "Defective should have all IDs"; + + boolean pass = ratio > 5.0; + System.out.println("RESULT: " + (pass ? "PASS" : "FAIL") + + " (ratio " + String.format("%.1f", ratio) + "x, threshold 5x)"); + if (!pass) System.exit(1); + } +} diff --git a/defects/zenoss/CLEAN.md b/defects/zenoss/CLEAN.md new file mode 100644 index 000000000..a8f4b51f7 --- /dev/null +++ b/defects/zenoss/CLEAN.md @@ -0,0 +1,20 @@ +# Zenoss CWE-407 Scan — CLEAN + +Scanned: 2026-03-30 +Target: zenoss-prodbin (https://github.com/zenoss/zenoss-prodbin) +Language: Python + +## Scan Summary + +Zenoss uses Zope catalogs, OrderedDict, dicts, and sets throughout its +codebase for data lookups and dedup. Key findings: + +- **Event dedup**: Uses OrderedDict (O(1) fingerprint lookup) — clean +- **Device/component lookups**: Uses catalog queries (indexed) — clean +- **Collection dedup**: Uses set for tid tracking — clean +- **Link manager**: Uses set subtraction for visited tracking — clean +- **Config cache**: Uses model index queries — clean + +No CWE-407 defects found with sufficient severity for a hot-path impact. +Minor O(N×M) patterns exist (MibModule.deleteMibNodes, ZenPackCmd dependency +resolution) but operate on small, user-bounded inputs.