v4.0.0: codec 2.60.4 security release, --pq-box sealed-box mode, F-16 fix
Some checks failed
CI / build-and-test (clang) (push) Has been cancelled
CI / build-and-test (gcc) (push) Has been cancelled
CI / strict-warnings (clang, -Wall -Wextra -Wpedantic -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -O2 -std=c11 -Werror) (push) Has been cancelled
CI / strict-warnings (gcc, -Wall -Wextra -Wpedantic -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -Wformat-security -Wlogical-op -Wjump-misses-init -Wdouble-promotion -O2 -std=c11 -Werror) (push) Has been cancelled
CI / sanitizers (push) Has been cancelled
CI / pie-hardening (push) Has been cancelled
CI / cross-aarch64 (push) Has been cancelled
CI / dist-reproducibility (push) Has been cancelled
CI / packaging-syntax (push) Has been cancelled
CI / release (push) Has been cancelled
Some checks failed
CI / build-and-test (clang) (push) Has been cancelled
CI / build-and-test (gcc) (push) Has been cancelled
CI / strict-warnings (clang, -Wall -Wextra -Wpedantic -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -O2 -std=c11 -Werror) (push) Has been cancelled
CI / strict-warnings (gcc, -Wall -Wextra -Wpedantic -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -Wformat-security -Wlogical-op -Wjump-misses-init -Wdouble-promotion -O2 -std=c11 -Werror) (push) Has been cancelled
CI / sanitizers (push) Has been cancelled
CI / pie-hardening (push) Has been cancelled
CI / cross-aarch64 (push) Has been cancelled
CI / dist-reproducibility (push) Has been cancelled
CI / packaging-syntax (push) Has been cancelled
CI / release (push) Has been cancelled
Major release. Highlights: - Codec: vendored VaptVupt codec moves to canonical 2.60.4 security release. Fixes a high-severity OOB heap write in the AVX2 decode fast path (reachable on a valid stream sized to exactly content_size, both tail variants). Brings CBMC-formally-verified BCJ filters with automatic ELF/PE/Mach-O detection. Compressed output stays byte-identical (ratio gate Δ 0.00%); wire format unchanged at v1.6. - New --pq-box sealed-box recipient mode (vendored libpqvaptvupt 0.6.0): ML-KEM-768 + X25519 combined via HKDF-SHA256 with domain separation, AES-256-CTR + HMAC-SHA256 EtM. Legacy --pq and --pq-sdk stay readable. - F-16: discloses and fixes a pre-existing data-loss defect in the <= 3.8.0 in-tree BCJ encoder. Full back-compat matrix decodes byte-exact under 4.0.0; every readable pre-4.0 archive remains readable. Repository hygiene: - Sync full 4.0.0 source tree (codec, crypto, SDK, GUI, packaging, tests). - Remove internal scratch files (PROMPT.md, FORMAL_AUDIT_PROMPT.md) and superseded version-specific docs (INTEGRATION_PROTOCOL_2.60.4.md, docs/FINDINGS-2.x.md) and a stray test binary. - Refresh README download/install section to real 4.0.0 release assets; bump version badge to 4.0.0. - Add .gitignore for build outputs (keeps vendored prebuilt libraries).
This commit is contained in:
parent
7619c4c577
commit
544a2cd647
98 changed files with 15615 additions and 1397 deletions
120
tests/test_codec_exact_size.c
Normal file
120
tests/test_codec_exact_size.c
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
*
|
||||
* Exact-content_size decode regression (v4.0.0; codec 2.60.4).
|
||||
*
|
||||
* Codec 2.60.4 fixes a high-severity OOB heap WRITE in the AVX2 decode
|
||||
* fast path, reachable on a VALID stream when the destination buffer is
|
||||
* sized to exactly content_size — two variants: a single wide store for
|
||||
* tails n <= 32, and the tail store for n > 32. The tool itself always
|
||||
* over-allocates (ZUPT_VV_DECODE_SLACK, F-14), so it was shielded; this
|
||||
* test pins the vendored codec directly so the defect class cannot
|
||||
* silently return via a future codec drop-in.
|
||||
*
|
||||
* Method: for payloads chosen to exercise (a) sizes whose tail mod 32
|
||||
* spans 1..32 and >32, (b) compressible text, (c) BCJ-triggering
|
||||
* ELF-like content (auto-filter on), compress with the same options the
|
||||
* tool's shim uses (BALANCED and EXTREME, format_v2, filter_auto), then
|
||||
* decompress into a heap buffer of EXACTLY the original size, under
|
||||
* AddressSanitizer. Any OOB write aborts the test. Output must also be
|
||||
* byte-identical to the input (BCJ inverse correctness).
|
||||
*/
|
||||
#include "vaptvupt.h"
|
||||
#include "vaptvupt_api.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static int run_case(const uint8_t *src, size_t n, int mode, const char *label) {
|
||||
vv_options_t opts;
|
||||
vv_default_options(&opts);
|
||||
opts.checksum = 0;
|
||||
opts.compat_v246_5_decoder = 0;
|
||||
opts.mode = mode;
|
||||
opts.format_v2 = 1;
|
||||
opts.filter_auto = 1;
|
||||
opts.window_log = 0;
|
||||
|
||||
size_t cap = vv_compress_bound(n);
|
||||
uint8_t *comp = (uint8_t *)malloc(cap);
|
||||
if (!comp) { fprintf(stderr, " OOM\n"); return 1; }
|
||||
int64_t csz = vv_compress(src, n, comp, cap, &opts);
|
||||
if (csz <= 0) { fprintf(stderr, " %s: compress failed (%lld)\n", label, (long long)csz); free(comp); return 1; }
|
||||
|
||||
/* EXACT-size destination — the CVE trigger. ASan owns the verdict on
|
||||
* any out-of-bounds write. */
|
||||
uint8_t *out = (uint8_t *)malloc(n ? n : 1);
|
||||
if (!out) { free(comp); return 1; }
|
||||
int64_t dsz = vv_decompress_flags(comp, (size_t)csz, out, n,
|
||||
VV_DECOMPRESS_SKIP_CHECKSUM);
|
||||
int rc = 0;
|
||||
if (dsz != (int64_t)n) { fprintf(stderr, " %s: size %lld != %zu\n", label, (long long)dsz, n); rc = 1; }
|
||||
else if (memcmp(out, src, n) != 0) { fprintf(stderr, " %s: payload mismatch\n", label); rc = 1; }
|
||||
free(out); free(comp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Synthetic ELF-ish buffer: real ELF magic + class/endian bytes so
|
||||
* vv_bcj_detect engages the x86 filter, then bytes containing E8/E9
|
||||
* (call/jmp rel32) patterns that the filter actually rewrites. */
|
||||
static void fill_elfish(uint8_t *p, size_t n) {
|
||||
static const uint8_t elf_hdr[20] = {
|
||||
0x7f,'E','L','F', 2,1,1,0, 0,0,0,0,0,0,0,0, 2,0, 0x3e,0
|
||||
};
|
||||
memset(p, 0, n);
|
||||
memcpy(p, elf_hdr, n < 20 ? n : 20);
|
||||
for (size_t i = 24; i + 5 < n; i += 7) {
|
||||
p[i] = (i % 3) ? 0xE8 : 0xE9; /* call / jmp */
|
||||
uint32_t rel = (uint32_t)(i * 2654435761u);
|
||||
memcpy(p + i + 1, &rel, 4);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("Codec exact-content_size decode (OOB regression, codec 2.60.4)\n");
|
||||
srand(424242);
|
||||
int fail = 0, pass = 0;
|
||||
|
||||
/* Tail coverage: n mod 32 in {1, 7, 31, 32 (0), >32 leftovers} at
|
||||
* block-ish sizes, plus tiny buffers. */
|
||||
static const size_t sizes[] = {
|
||||
1, 7, 31, 32, 33, 63, 64, 65, 96, 4095, 4096, 4097,
|
||||
65536 + 1, 65536 + 31, 65536 + 33, 1048576 + 17
|
||||
};
|
||||
enum { NSZ = sizeof(sizes)/sizeof(sizes[0]) };
|
||||
|
||||
uint8_t *buf = (uint8_t *)malloc(1048576 + 64);
|
||||
if (!buf) return 1;
|
||||
|
||||
for (int k = 0; k < NSZ; k++) {
|
||||
size_t n = sizes[k];
|
||||
char label[96];
|
||||
|
||||
/* compressible text-like */
|
||||
for (size_t i = 0; i < n; i++) buf[i] = (uint8_t)("abcdef \n"[i % 8]);
|
||||
snprintf(label, sizeof label, "text n=%zu BALANCED", n);
|
||||
if (run_case(buf, n, VV_MODE_BALANCED, label)) fail++; else pass++;
|
||||
snprintf(label, sizeof label, "text n=%zu EXTREME", n);
|
||||
if (run_case(buf, n, VV_MODE_EXTREME, label)) fail++; else pass++;
|
||||
|
||||
/* BCJ-triggering ELF-ish (filter_auto fires) */
|
||||
fill_elfish(buf, n);
|
||||
snprintf(label, sizeof label, "elf n=%zu BALANCED", n);
|
||||
if (run_case(buf, n, VV_MODE_BALANCED, label)) fail++; else pass++;
|
||||
snprintf(label, sizeof label, "elf n=%zu EXTREME", n);
|
||||
if (run_case(buf, n, VV_MODE_EXTREME, label)) fail++; else pass++;
|
||||
|
||||
/* incompressible (stored path) */
|
||||
for (size_t i = 0; i < n; i++) buf[i] = (uint8_t)rand();
|
||||
snprintf(label, sizeof label, "rand n=%zu BALANCED", n);
|
||||
if (run_case(buf, n, VV_MODE_BALANCED, label)) fail++; else pass++;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
printf("\n ───────────────────────────────────────\n");
|
||||
printf(" exact-size decode: %d passed, %d failed\n", pass, fail);
|
||||
printf(" ───────────────────────────────────────\n");
|
||||
return fail ? 1 : 0;
|
||||
}
|
||||
Loading…
Reference in a new issue