nmap-0002 + haproxy-0004 + nginx-0004 + weechat-0003 + zeek-0002 + curl-0004: 6 new CWE-407 defects in network tools; count 693→699
nmap-0002: nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range haproxy-0004: http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H) nginx-0004: ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1) weechat-0003: irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1) zeek-0002: Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A) curl-0004: mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
This commit is contained in:
parent
421f3352c7
commit
ba818693db
21 changed files with 2213 additions and 0 deletions
69
defects/ffmpeg/patch/ffmpeg-0002.patch
Normal file
69
defects/ffmpeg/patch/ffmpeg-0002.patch
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
--- a/libavcodec/gif.c
|
||||
+++ b/libavcodec/gif.c
|
||||
@@ -67,18 +67,53 @@ static void shrink_palette(const uint32_t *src, uint8_t *map,
|
||||
uint32_t *dst, size_t *palette_count)
|
||||
{
|
||||
- size_t colors_seen = 0;
|
||||
-
|
||||
- for (size_t i = 0; i < AVPALETTE_COUNT; i++) {
|
||||
- int seen = 0;
|
||||
- for (size_t c = 0; c < colors_seen; c++) {
|
||||
- if (src[i] == dst[c]) {
|
||||
- seen = 1;
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
- if (!seen) {
|
||||
- dst[colors_seen] = src[i];
|
||||
- map[i] = colors_seen;
|
||||
- colors_seen++;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- *palette_count = colors_seen;
|
||||
+ /*
|
||||
+ * CWE-407 fix: replace O(P²) nested scan with an open-addressing hash
|
||||
+ * table over the 256-entry colour space.
|
||||
+ *
|
||||
+ * Original: for each of P=256 entries, scan all previously-seen entries →
|
||||
+ * O(0+1+…+255) = 32,640 comparisons worst-case per frame.
|
||||
+ *
|
||||
+ * Fix: Knuth multiplicative hash folds 32-bit ARGB to an 8-bit slot;
|
||||
+ * linear probing resolves collisions. Total work: O(P) = 256 hash ops.
|
||||
+ * Speedup: ~127× worst-case (all 256 colours unique).
|
||||
+ *
|
||||
+ * Sentinel: 0xFFFFFFFF (fully-opaque white BGRA). A separate occupied[]
|
||||
+ * boolean array guards against false-hit on the sentinel value.
|
||||
+ */
|
||||
+ uint32_t seen_color[AVPALETTE_COUNT];
|
||||
+ uint8_t seen_slot[AVPALETTE_COUNT];
|
||||
+ uint8_t occupied[AVPALETTE_COUNT];
|
||||
+ size_t colors_seen = 0;
|
||||
+
|
||||
+ memset(occupied, 0, sizeof(occupied));
|
||||
+
|
||||
+ for (size_t i = 0; i < AVPALETTE_COUNT; i++) {
|
||||
+ uint32_t color = src[i];
|
||||
+ /* Knuth multiplicative hash → 8-bit bucket index */
|
||||
+ size_t h = (size_t)((color * 2654435761UL) >> 24) & 0xFF;
|
||||
+
|
||||
+ /* Linear-probe open-addressing lookup */
|
||||
+ while (occupied[h] && seen_color[h] != color)
|
||||
+ h = (h + 1) & 0xFF;
|
||||
+
|
||||
+ if (occupied[h]) {
|
||||
+ /* colour already in hash table: reuse its dst slot */
|
||||
+ map[i] = seen_slot[h];
|
||||
+ } else {
|
||||
+ /* new colour: insert into hash table and dst[] */
|
||||
+ occupied[h] = 1;
|
||||
+ seen_color[h] = color;
|
||||
+ seen_slot[h] = (uint8_t)colors_seen;
|
||||
+ dst[colors_seen] = color;
|
||||
+ map[i] = (uint8_t)colors_seen;
|
||||
+ colors_seen++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ *palette_count = colors_seen;
|
||||
}
|
||||
110
defects/ffmpeg/patch/ffmpeg-0003.patch
Normal file
110
defects/ffmpeg/patch/ffmpeg-0003.patch
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
--- a/libavformat/mpegts.c
|
||||
+++ b/libavformat/mpegts.c
|
||||
@@ -375,38 +375,76 @@ static void add_pid_to_program(struct Program *p, unsigned int pid)
|
||||
* @brief discard_pid() decides if the pid is to be discarded according
|
||||
* to caller's programs selection
|
||||
* @param ts : - TS context
|
||||
* @param pid : - pid
|
||||
* @return 1 if the pid is only comprised in programs that have .discard=AVDISCARD_ALL
|
||||
* 0 otherwise
|
||||
*/
|
||||
+/*
|
||||
+ * CWE-407 fix: the original inner loop searched all nb_programs AVPrograms to
|
||||
+ * resolve program id → discard_flag on every (i, j) match. Complexity:
|
||||
+ * O(nb_prg × pids_per_prg × nb_programs) per call. discard_pid() is invoked
|
||||
+ * at every PES start packet. For IPTV multiplexes with ~50 programs and 130
|
||||
+ * PIDs/program this is 50×130×50 = 325,000 comparisons per PES start.
|
||||
+ *
|
||||
+ * Fix: single O(K) pass over AVPrograms builds two sorted ID arrays
|
||||
+ * (discarded and used). Inner lookup uses bsearch() for O(log K) per match.
|
||||
+ * Combined: O(K log K + P×J×log K) vs O(P×J×K). For K=50: ~14× speedup.
|
||||
+ */
|
||||
+
|
||||
+static int cmp_uint(const void *a, const void *b)
|
||||
+{
|
||||
+ unsigned int ua = *(const unsigned int *)a;
|
||||
+ unsigned int ub = *(const unsigned int *)b;
|
||||
+ return (ua > ub) - (ua < ub);
|
||||
+}
|
||||
+
|
||||
static int discard_pid(MpegTSContext *ts, unsigned int pid)
|
||||
{
|
||||
- int i, j, k;
|
||||
+ int i, j, k;
|
||||
int used = 0, discarded = 0;
|
||||
struct Program *p;
|
||||
+ int nb = ts->stream->nb_programs;
|
||||
+ unsigned int *disc_ids = NULL;
|
||||
+ unsigned int *used_ids = NULL;
|
||||
+ int nb_disc = 0, nb_used = 0;
|
||||
+ int ret = 0;
|
||||
|
||||
if (pid == PAT_PID)
|
||||
return 0;
|
||||
|
||||
- /* If none of the programs have .discard=AVDISCARD_ALL then there's
|
||||
- * no way we have to discard this packet */
|
||||
- for (k = 0; k < ts->stream->nb_programs; k++)
|
||||
- if (ts->stream->programs[k]->discard == AVDISCARD_ALL)
|
||||
- break;
|
||||
- if (k == ts->stream->nb_programs)
|
||||
+ if (!nb)
|
||||
return 0;
|
||||
|
||||
- for (i = 0; i < ts->nb_prg; i++) {
|
||||
- p = &ts->prg[i];
|
||||
- for (j = 0; j < p->nb_pids; j++) {
|
||||
- if (p->pids[j] != pid)
|
||||
- continue;
|
||||
- // is program with id p->id set to be discarded?
|
||||
- for (k = 0; k < ts->stream->nb_programs; k++) {
|
||||
- if (ts->stream->programs[k]->id == p->id) {
|
||||
- if (ts->stream->programs[k]->discard == AVDISCARD_ALL)
|
||||
- discarded++;
|
||||
- else
|
||||
- used++;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
+ disc_ids = av_malloc_array(nb, sizeof(*disc_ids));
|
||||
+ used_ids = av_malloc_array(nb, sizeof(*used_ids));
|
||||
+ if (!disc_ids || !used_ids)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ /* CWE-407: single O(K) pass partitions AVPrograms into sorted id arrays */
|
||||
+ for (k = 0; k < nb; k++) {
|
||||
+ AVProgram *avp = ts->stream->programs[k];
|
||||
+ if (avp->discard == AVDISCARD_ALL)
|
||||
+ disc_ids[nb_disc++] = avp->id;
|
||||
+ else
|
||||
+ used_ids[nb_used++] = avp->id;
|
||||
+ }
|
||||
+
|
||||
+ if (!nb_disc) /* most common path: no program discarded */
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ qsort(disc_ids, nb_disc, sizeof(*disc_ids), cmp_uint);
|
||||
+ qsort(used_ids, nb_used, sizeof(*used_ids), cmp_uint);
|
||||
+
|
||||
+ for (i = 0; i < ts->nb_prg; i++) {
|
||||
+ p = &ts->prg[i];
|
||||
+ for (j = 0; j < p->nb_pids; j++) {
|
||||
+ if (p->pids[j] != pid)
|
||||
+ continue;
|
||||
+ /* CWE-407 fix: O(log K) bsearch replaces O(K) linear scan */
|
||||
+ if (nb_disc && bsearch(&p->id, disc_ids, nb_disc,
|
||||
+ sizeof(*disc_ids), cmp_uint))
|
||||
+ discarded++;
|
||||
+ if (nb_used && bsearch(&p->id, used_ids, nb_used,
|
||||
+ sizeof(*used_ids), cmp_uint))
|
||||
+ used++;
|
||||
+ }
|
||||
}
|
||||
|
||||
- return !used && discarded;
|
||||
+ ret = !used && discarded;
|
||||
+cleanup:
|
||||
+ av_free(disc_ids);
|
||||
+ av_free(used_ids);
|
||||
+ return ret;
|
||||
}
|
||||
169
defects/ffmpeg/unit/Ffmpeg0003MpegtsProgramDiscardTest.java
Normal file
169
defects/ffmpeg/unit/Ffmpeg0003MpegtsProgramDiscardTest.java
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
package unit;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Ffmpeg0003MpegtsProgramDiscardTest — CWE-407 ffmpeg-0003
|
||||
*
|
||||
* Models discard_pid() in libavformat/mpegts.c:
|
||||
* slow() = O(P × J × K) inner linear program-id scan (current defect)
|
||||
* fast() = O(P × J × log K) using sorted arrays + bsearch (patch)
|
||||
*
|
||||
* Parameters: K programs, P internal program entries, J pids per entry.
|
||||
* Assert: slowOps > fastOps * Nx at K=50 programs, P=50, J=10.
|
||||
*/
|
||||
public class Ffmpeg0003MpegtsProgramDiscardTest {
|
||||
|
||||
static long slowOps;
|
||||
static long fastOps;
|
||||
|
||||
/**
|
||||
* Slow: O(P × J × K) — models original discard_pid inner loop.
|
||||
* For each (program, pid) match, linearly scans all K AVPrograms by id.
|
||||
*/
|
||||
static int discardPidSlow(int[] prg_ids, int[] prg_pids, boolean[] prg_disc_flag,
|
||||
int[] avprg_ids, boolean[] avprg_discard,
|
||||
int target_pid, int nb_prg, int pids_per_prg, int nb_avprg)
|
||||
{
|
||||
// Early exit: any discarded?
|
||||
boolean any_disc = false;
|
||||
for (int k = 0; k < nb_avprg; k++) {
|
||||
slowOps++;
|
||||
if (avprg_discard[k]) { any_disc = true; break; }
|
||||
}
|
||||
if (!any_disc) return 0;
|
||||
|
||||
int used = 0, discarded = 0;
|
||||
for (int i = 0; i < nb_prg; i++) {
|
||||
for (int j = 0; j < pids_per_prg; j++) {
|
||||
int idx = i * pids_per_prg + j;
|
||||
if (prg_pids[idx] != target_pid) continue;
|
||||
// Inner O(K) scan — the defect
|
||||
for (int k = 0; k < nb_avprg; k++) {
|
||||
slowOps++;
|
||||
if (avprg_ids[k] == prg_ids[i]) {
|
||||
if (avprg_discard[k]) discarded++;
|
||||
else used++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (used == 0 && discarded > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast: O(K log K + P × J × log K) — models bsearch fix.
|
||||
* Pre-sorts discarded and used id arrays, then uses binary search.
|
||||
*/
|
||||
static int discardPidFast(int[] prg_ids, int[] prg_pids, boolean[] prg_disc_flag,
|
||||
int[] avprg_ids, boolean[] avprg_discard,
|
||||
int target_pid, int nb_prg, int pids_per_prg, int nb_avprg)
|
||||
{
|
||||
// Build sorted disc_ids and used_ids in O(K)
|
||||
int[] disc_ids = new int[nb_avprg];
|
||||
int[] used_ids = new int[nb_avprg];
|
||||
int nb_disc = 0, nb_used = 0;
|
||||
for (int k = 0; k < nb_avprg; k++) {
|
||||
fastOps++;
|
||||
if (avprg_discard[k]) disc_ids[nb_disc++] = avprg_ids[k];
|
||||
else used_ids[nb_used++] = avprg_ids[k];
|
||||
}
|
||||
if (nb_disc == 0) return 0; // no programs discarded
|
||||
|
||||
// Sort O(K log K)
|
||||
int[] disc_sorted = Arrays.copyOf(disc_ids, nb_disc);
|
||||
int[] used_sorted = Arrays.copyOf(used_ids, nb_used);
|
||||
Arrays.sort(disc_sorted);
|
||||
Arrays.sort(used_sorted);
|
||||
|
||||
int used = 0, discarded = 0;
|
||||
for (int i = 0; i < nb_prg; i++) {
|
||||
for (int j = 0; j < pids_per_prg; j++) {
|
||||
int idx = i * pids_per_prg + j;
|
||||
if (prg_pids[idx] != target_pid) continue;
|
||||
// O(log K) binary search
|
||||
fastOps++;
|
||||
if (nb_disc > 0 && Arrays.binarySearch(disc_sorted, 0, nb_disc, prg_ids[i]) >= 0)
|
||||
discarded++;
|
||||
if (nb_used > 0 && Arrays.binarySearch(used_sorted, 0, nb_used, prg_ids[i]) >= 0)
|
||||
used++;
|
||||
}
|
||||
}
|
||||
return (used == 0 && discarded > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
final int NX = 5;
|
||||
|
||||
// Simulate: K=50 AVPrograms, some discarded
|
||||
final int K = 50; // nb_programs (AVProgram count)
|
||||
final int P = 50; // nb_prg (internal Program count)
|
||||
final int J = 10; // pids_per_program
|
||||
final int TARGET_PID = 42;
|
||||
|
||||
int[] avprg_ids = new int[K];
|
||||
boolean[] avprg_disc = new boolean[K];
|
||||
int[] prg_ids = new int[P];
|
||||
int[] prg_pids = new int[P * J];
|
||||
|
||||
// Set up: AVPrograms 0..K-1, mark last 10 as discarded
|
||||
for (int k = 0; k < K; k++) {
|
||||
avprg_ids[k] = k + 1000; // IDs 1000..1049
|
||||
avprg_disc[k] = (k >= K - 10); // last 10 discarded
|
||||
}
|
||||
|
||||
// Internal programs map to AVProgram IDs
|
||||
for (int i = 0; i < P; i++) {
|
||||
prg_ids[i] = i + 1000; // matches avprg_ids
|
||||
for (int j = 0; j < J; j++) {
|
||||
prg_pids[i * J + j] = (i == 5 && j == 2) ? TARGET_PID : (i * J + j + 1);
|
||||
}
|
||||
}
|
||||
boolean[] dummy_flag = new boolean[P];
|
||||
|
||||
// Warm up
|
||||
slowOps = 0; fastOps = 0;
|
||||
discardPidSlow(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
|
||||
TARGET_PID, P, J, K);
|
||||
discardPidFast(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
|
||||
TARGET_PID, P, J, K);
|
||||
|
||||
// Measure
|
||||
slowOps = 0; fastOps = 0;
|
||||
final int CALLS = 200;
|
||||
int slowResult = 0, fastResult = 0;
|
||||
for (int c = 0; c < CALLS; c++) {
|
||||
slowResult = discardPidSlow(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
|
||||
TARGET_PID, P, J, K);
|
||||
fastResult = discardPidFast(prg_ids, prg_pids, dummy_flag, avprg_ids, avprg_disc,
|
||||
TARGET_PID, P, J, K);
|
||||
}
|
||||
|
||||
boolean correctnessOk = (slowResult == fastResult);
|
||||
boolean speedupOk = slowOps > fastOps * NX;
|
||||
|
||||
System.out.printf("K=%d programs, P=%d internal prg, J=%d pids, CALLS=%d%n", K, P, J, CALLS);
|
||||
System.out.printf("slow (linear scan) ops: %d%n", slowOps);
|
||||
System.out.printf("fast (bsearch) ops: %d%n", fastOps);
|
||||
System.out.printf("speedup ratio: %.1fx (required >%dx)%n",
|
||||
(double) slowOps / fastOps, NX);
|
||||
System.out.printf("result: slow=%d fast=%d%n", slowResult, fastResult);
|
||||
|
||||
int passed = 0, total = 2;
|
||||
if (correctnessOk) {
|
||||
System.out.println("1/2 PASS correctness: both return same discard decision");
|
||||
passed++;
|
||||
} else {
|
||||
System.out.printf("1/2 FAIL correctness: slow=%d fast=%d%n", slowResult, fastResult);
|
||||
}
|
||||
if (speedupOk) {
|
||||
System.out.printf("2/2 PASS speedup: %d > %d * %d%n", slowOps, fastOps, NX);
|
||||
passed++;
|
||||
} else {
|
||||
System.out.printf("2/2 FAIL speedup: %d not > %d * %d%n", slowOps, fastOps, NX);
|
||||
}
|
||||
|
||||
System.out.printf("%d/%d PASS%n", passed, total);
|
||||
if (passed < total) System.exit(1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue