Files
proxmark3/tools
iceman1001andClaude Opus 5 (1M context) 584624a624 fpga_compress: stop rejecting a bitstream set that exactly fills the buffer
PLATFORM=PM3ULTIMATE has not built since c0ecb1c62 (2026-04-14), which
fixed a real heap overflow by changing one character:

    -        if (total_size > num_infiles * FPGA_CONFIG_SIZE) {
    +        if (total_size >= num_infiles * FPGA_CONFIG_SIZE) {

The old '>' checked after the fact, so a round could start with the
buffer already full and write num_infiles * FPGA_INTERLEAVE_SIZE bytes
past the end. But '>=' answers the wrong question: a buffer that is
exactly full is not an error, it is the expected end state for a
platform whose bitstreams are sized to FPGA_CONFIG_SIZE.

Two things had to change.

all_feof() tested the EOF flag, and C only sets that once a read has
already run off the end -- consuming the last byte of a file leaves it
clear. A file whose length is an exact multiple of FPGA_INTERLEAVE_SIZE
therefore still looked unfinished after its final whole chunk, and the
interleave loop ran one more round of pure zero padding. It now peeks a
byte with fgetc/ungetc instead, so a file read to its last byte counts
as finished right away.

PM3ULTIMATE is the only platform this reaches:

    fpga_pm3_ult_felica.bit   69984   = 243 * 288 exactly
    fpga_pm3_ult_hf_15.bit    69983
    fpga_pm3_ult_hf.bit       69980
    fpga_pm3_ult_lf.bit       69980

243 rounds * 4 files * 288 = 279936, which is exactly
4 * FPGA_CONFIG_SIZE for 2s50vq144. Round 244 was padding only, and '>='
killed it there. Stock PM3's largest bitstream is 42172, not a chunk
multiple, so its last round trips feof naturally and it never gets that
far -- which is why this went unnoticed, nothing in CI builds ULTIMATE.

The guard now asks whether the next round fits, which is the condition
it was always meant to express and is strictly stronger than the
original '>':

    if (total_size + (num_infiles * FPGA_INTERLEAVE_SIZE) > num_infiles * FPGA_CONFIG_SIZE)

Verified: PM3ULTIMATE compresses 279936 bytes to 40195 and all four
bitstreams decompress back byte-exact. Output is byte-identical to
before for stock 2s30vq100 (169344 -> 106628), for icopyx XC3
(72864 -> 27292) and for the '-s' .data section path. fullimage builds
for PM3ULTIMATE, PM3RDV4, PM3GENERIC and PM5.

Note FPGA_CONFIG_SIZE is now exactly the size of the largest ULTIMATE
bitstream. Regenerate that one byte larger and the guard fires again,
correctly; bump the constant by one interleave step rather than touching
the guard.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-14 18:12:16 +02:00
..
2023-05-27 17:00:28 +02:00
2026-08-19 19:28:17 +02:00
2026-07-15 16:39:15 +02:00
2026-06-07 23:01:20 +02:00
2022-12-31 10:03:17 +01:00
2025-04-29 11:33:22 -04:00
2026-08-29 17:15:52 +02:00
2021-10-06 20:06:17 +02:00
2024-01-07 18:05:48 +01:00
2022-02-13 12:19:06 +01:00
2021-10-06 20:27:55 +02:00
2026-09-03 19:31:56 +02:00
2023-10-15 10:11:27 +02:00
2021-10-06 20:27:55 +02:00
2021-10-06 20:27:55 +02:00
2024-09-13 13:44:16 +02:00
2026-09-13 12:55:43 +02:00
2021-10-06 20:27:55 +02:00
2026-03-23 22:36:47 +01:00