import java.util.*; /** * CWE-407 unit test for wireshark defect. * * wireshark-0001: proto_data.c — per-packet proto data GSList O(N) lookup * p_set_proto_data / p_get_proto_data / p_remove_proto_data each do * g_slist_find_custom(pinfo->proto_data, ...) — O(N) scan over all * per-packet protocol data entries. Called repeatedly per dissector layer. * * Fix: replace GSList with wmem_map_t keyed by (proto<<32 | key) → O(1). */ public class WiresharkTest { // Simulate GSList-based proto_data (defect) static class ProtoDataList { private final List entries = new ArrayList<>(); // [proto, key, data_id] void set(int proto, long key, long data) { long compKey = ((long) proto << 32) | (key & 0xFFFFFFFFL); for (long[] e : entries) { // O(N) scan if (e[0] == compKey) { e[1] = data; return; } } entries.add(new long[]{compKey, data}); } long get(int proto, long key) { long compKey = ((long) proto << 32) | (key & 0xFFFFFFFFL); for (long[] e : entries) { // O(N) scan if (e[0] == compKey) return e[1]; } return -1; } } // Simulate wmem_map_t-based proto_data (fix) static class ProtoDataMap { private final Map map = new HashMap<>(); void set(int proto, long key, long data) { map.put(((long) proto << 32) | (key & 0xFFFFFFFFL), data); } long get(int proto, long key) { Long v = map.get(((long) proto << 32) | (key & 0xFFFFFFFFL)); return v != null ? v : -1; } } static void testWireshark0001() throws Exception { int N = 300; // dissector layers per packet (complex capture) int PROTOS = 50; Random rng = new Random(42); // build test data: N (proto, key, value) tuples int[][] queries = new int[N][2]; for (int i = 0; i < N; i++) { queries[i][0] = rng.nextInt(PROTOS); queries[i][1] = rng.nextInt(1000); } // correctness: both implementations return same values after inserts ProtoDataList plist = new ProtoDataList(); ProtoDataMap pmap = new ProtoDataMap(); for (int i = 0; i < N; i++) { plist.set(queries[i][0], queries[i][1], i); pmap.set(queries[i][0], queries[i][1], i); } for (int i = 0; i < N; i++) { long vlist = plist.get(queries[i][0], queries[i][1]); long vmap = pmap.get(queries[i][0], queries[i][1]); assert vlist == vmap : "mismatch at " + i + ": " + vlist + " vs " + vmap; } // performance: simulate per-packet dissection — build once, many repeated lookups // (dissectors call p_get_proto_data repeatedly on the same pinfo per packet) long t0 = System.nanoTime(); for (int pkt = 0; pkt < 200; pkt++) { ProtoDataList pd = new ProtoDataList(); for (int i = 0; i < N; i++) pd.set(queries[i][0], queries[i][1], i); // simulate many get calls on a fully-populated list (N entries → each get is O(N/2)) for (int rep = 0; rep < 50; rep++) for (int i = 0; i < N; i++) pd.get(queries[i][0], queries[i][1]); } long tList = System.nanoTime() - t0; t0 = System.nanoTime(); for (int pkt = 0; pkt < 200; pkt++) { ProtoDataMap pd = new ProtoDataMap(); for (int i = 0; i < N; i++) pd.set(queries[i][0], queries[i][1], i); for (int rep = 0; rep < 50; rep++) for (int i = 0; i < N; i++) pd.get(queries[i][0], queries[i][1]); } long tMap = System.nanoTime() - t0; double ratio = (double) tList / tMap; System.out.printf("wireshark-0001: list=%.3fs map=%.3fs ratio=%.1f×%n", tList / 1e9, tMap / 1e9, ratio); assert ratio > 5 : "Expected >5× speedup, got " + ratio; System.out.println("PASS wireshark-0001"); } public static void main(String[] args) throws Exception { testWireshark0001(); System.out.println("ALL PASS"); } }