Commit Graph
56 Commits
Author SHA1 Message Date
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
iceman1001andClaude Opus 5 (1M context) f0b569b507 fpga_compress: pad a single bitstream to the interleave boundary
zlib_decompress() walks its output in whole FPGA_INTERLEAVE_SIZE chunks:

  for (long k = 0; k < *outsize / (FPGA_INTERLEAVE_SIZE * num_outfiles); k++)

so a stream that is not a whole number of chunks loses its trailing partial one.
With two or more inputs the read loop zero-pads each stream past EOF and the
total lands on a boundary, but the padding was guarded by 'num_infiles > 1', so
the single input case was left ragged. 42172 bytes of fpga_pm3_hf.bit is 146.43
chunks, and -d handed back 39788 - a clean looking prefix, short by 2384 bytes,
22 of them real bitstream data.

Gate the padding on single_block instead. It must not be 'always pad': -s is the
.data section, and start.c's uncompress_data_section() sizes the decompression
with __data_end__ - __data_start__. Rounding .data from 14944 up to 14976 makes
LZ4_decompress_safe() return an error, and that path is the LED panic loop, so
the firmware would never reach AppMain().

  1 bitstream   42172 in -> 42336 packed, -d round trip byte identical,
                archive 28730 -> 28731
  4 bitstreams  archive byte identical to 43fe6c3eb, round trip exact
  -s .data      byte identical to 43fe6c3eb on the same input, unpadded

The 164 padding bytes never reach the FPGA: DownloadFPGA() shifts out only
bitstream_length bytes, taken from the .bit 'e' section header.

Also simulated the ARM decoder over the new archive - LZ4_decompress_safe_continue()
block by block into a FPGA_RING_BUFFER_BYTES buffer - 3 blocks of 16384/16384/9568,
none over the ring buffer.

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-13 08:27:53 +02:00
iceman1001andClaude Opus 5 (1M context) 43fe6c3eb8 fpga_compress: pick the LZ4 block size by consumer, not by file count
The 1 MB block branch exists for the ARM .data section: start.c's
uncompress_data_section() reads one 4-byte length and does one
LZ4_decompress_safe(), so .data has to arrive as a single block. It was
selected by 'num_infiles == 1', which is not what tells the two callers apart.

A build that skips LF, FeliCa and ISO15693 leaves FPGA_BITSTREAMS holding just
fpga_pm3_hf.bit, so the bitstream took that same branch and was packed as one
42 kB block. get_from_fpga_combined_stream() decompresses into a
FPGA_RING_BUFFER_BYTES buffer, 16 kB since 83c3f81b1:

  [#] inflate returned: -13247
  [#] reset_fpga_stream failed

Before 83c3f81b1 the copy was clamped with MIN(FPGA_RING_BUFFER_BYTES, ...)
whatever buffer_size said, so the blocks came out at 30 kB and the 30 kB ring
buffer still took them. That is why the commit looks like the cause - it only
removed the clamp that was covering for the wrong branch.

Add -s for the single block case and let the FPGA path always chop at
FPGA_RING_BUFFER_BYTES, however many bitstreams went in:

  4 bitstreams   169344 in -> 106933 out, byte identical to before
  1 bitstream     42172 in ->  28718 out, 3 blocks 13265/13206/2247,
                                          was 1 block of 27627
  .data  (-s)     14944 in ->   8786 out, byte identical to the
                                          obj/fullimage.data.bin.z in tree

Also hand the ring buffer back when reset_fpga_stream() fails. The early
return left it allocated for the rest of the session, which is the reporter's

  [#]   BigBuf_size............. 48116
  [#]   Available memory........ 31732

48116 - 31732 is 16384, exactly FPGA_RING_BUFFER_BYTES.

No CAPABILITIES_VERSION bump: fpga_all.bit.z is objcopy'd into the same
fullimage as the decompressor that reads it, so nothing here is client facing.

Reported and correctly diagnosed by @ewangsoft.

Fixes #3599

Co-Authored-By: Claude Opus 5 (1M context)
2026-09-13 08:14:43 +02:00
iceman1001 83c3f81b1b move to 16kb fpga ring buffer size, recompile fullimage and lower stack size to 7160 bytes 2026-09-01 10:14:35 +02:00
Philippe Teuwen d8c7f84598 Add Makefile PLATFORM_FILE variable to specify another Makefile.platform file 2026-05-19 00:10:17 +02:00
Philippe Teuwen c0ecb1c626 fpga_compress: fix heap corruption 2026-04-14 10:14:38 +02:00
Philippe Teuwen 8f9bb379ad fix client Makefile if no Makefie.platform is provided 2025-07-13 11:57:26 +02:00
iceman1001 8c880e4a3f missed this one 2025-06-08 16:10:09 +02:00
iceman1001 875b3c44b4 unify text - step 1 2025-03-25 10:12:16 +01:00
Philippe Teuwen ad84875afd cppcheck nullPointerOutOfMemory 2025-03-24 23:46:43 +01:00
n-hutton 982bef6705 fix build failure on linux machines with fwd decl 2025-02-20 15:55:43 +00:00
n-hutton 3e9de01303 PR feedback 2025-02-18 15:49:33 +00:00
douniwan5788 413a17a7a6 feature: Make the FPGA bitstreams working with SKIP_* define.
Now, you can enable at least two of your favorite technologies (such as LF and HF 14443A) attached a standalone mode and still have spare ROM space for other functionalities on a Proxmark3 Easy with a 256KiB ROM.
2024-08-26 20:55:59 +08:00
nvx 8dd963d305 make style 2023-08-24 16:34:33 +10:00
Alex 6947a61d98 Whitespace 2023-08-09 14:30:07 +02:00
iceman1001 c6f2785463 wrong fcloses 2023-08-03 15:33:16 +02:00
iceman1001 33876ea892 adapting fpga_compress to free memory and close file handles in exceptions 2023-08-03 13:01:49 +02:00
iceman1001 b7900816bd checking if calloc failed 2023-07-24 03:16:18 +02:00
iceman1001 e43f6804a1 style 2023-07-06 22:37:34 +02:00
d18c7db c59bdec4f2 Unified fpga folders 2023-05-30 19:47:27 +02:00
iceman1001 bc46696dc4 unify license text 2022-03-20 09:31:53 +01:00
Philippe Teuwen 87ac62a869 fix some CodeQL warnings 2022-02-15 15:56:14 +01:00
iceman1001 7c7dfa7d39 cppcheck fix 2022-01-08 15:05:03 +01:00
Philippe Teuwen e79fb92074 Add fpga-xc3s100e and icopyx support 2021-08-21 23:45:46 +02:00
iceman1001 70709ca0ed fix coverity CID 349306 - resource leak 2021-06-20 11:13:49 +02:00
merlokk c5f24a24a4 make style and small fix 2021-06-17 13:44:14 +03:00
Philippe Teuwen 0059cec493 fpga_compress decompress: truncate output files 2021-06-15 10:15:51 +02:00
Philippe Teuwen 339fd909c6 fpga_compress: allow decompression routine to deinterleave output in multiple files 2021-06-07 22:40:42 +02:00
Philippe Teuwen 4c44138557 make style 2021-05-30 14:29:05 +02:00
iceman1001 436fedcbe4 fix coverity CID 344485, 344482, 344481 2021-05-20 10:11:41 +02:00
iceman1001 16c43bea2d fix coverity CID 322671, 322668, and time now is zero padded 2021-05-19 10:13:37 +02:00
Philippe Teuwen 79bf006419 Makefile: remove ROOT_DIR 2021-04-18 18:52:48 +02:00
iceman1001 31df889f97 cppchecker fix - format string 2021-01-28 12:42:32 +01:00
Philippe Teuwen 042342dc8f fpga_compress: fix mem leak 2020-10-06 16:57:04 +02:00
Philippe Teuwen 4ed57c7c4d make style 2020-08-13 12:25:04 +02:00
iceman1001 0d4c537ede version info for FeliCa fpga image 2020-07-08 11:05:04 +02:00
Philippe Teuwen 224cb2ffd7 make style 2020-06-08 03:15:10 +02:00
Philippe Teuwen fa0b658436 Remove zlib entirely, no need for fpga_compress anymore to compress hardnested tables, now to be compressed with bzip2 2020-06-08 02:50:43 +02:00
iceman1001 1bb7b041c0 resource leaks 2020-06-07 20:45:55 +02:00
iceman1001 5c43caa6b1 fix: ftell uses long int 2020-06-07 19:36:48 +02:00
iceman1001 9a2a5496c0 fix, resource leaks 2020-06-07 19:33:32 +02:00
Philippe Teuwen ef6b775f9f lz4/fpga_compress: avoid alignment problems
fpga_compress.c:176:32: warning: cast from 'char *' to 'int *' increases required alignment from 1 to 4 [-Wcast-align]
        const int cmp_bytes = *(int*)(compressed_fpga_stream.next_in);
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2020-06-07 13:10:59 +02:00
Philippe Teuwen df9f34ba2b lz4/fpga_compress: remove warning missing-braces
fpga_compress.c:154:49: error: suggest braces around initialization of subobject [-Werror,-Wmissing-braces]
    LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
                                                ^
                                                {}
2020-06-07 13:02:51 +02:00
slurdge cb03286420 fpga_compress uses lz4 2020-06-03 16:07:35 +02:00
Philippe Teuwen cb8d589fc4 armsrc: clarify static vars vs global vars, part 3 2020-05-19 18:12:40 +02:00
iceman1001 8a3f2d03ac style 2020-03-09 16:54:42 +01:00
iceman1001 bc3f0c4da8 fix: #555 fpga_compress missing tarbin directive 2020-02-12 09:52:23 +01:00
Philippe Teuwen 5ef4d6dbbb fpga_compress: no previous prototype warning 2019-10-26 18:32:38 +02:00
Philippe Teuwen c6220dc7be fpga_compress: unused parameter warning 2019-10-26 18:32:17 +02:00
Philippe Teuwen a5001de76c less magic trick in fpga_compress for coverity 2019-10-05 19:10:40 +02:00