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:
russell@unturf.com 2026-03-29 22:22:11 -04:00
parent 421f3352c7
commit ba818693db
21 changed files with 2213 additions and 0 deletions

View 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;
}

View 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;
}