Skip to content

Reject in place patches with segment size 0. - #20

Open
deadcaf3 wants to merge 1 commit into
eerimoq:masterfrom
deadcaf3:in-place-zero-segment-size
Open

deadcaf3 wants to merge 1 commit into
eerimoq:masterfrom
deadcaf3:in-place-zero-segment-size

Conversation

@deadcaf3

Copy link
Copy Markdown

The in place patch header's segment size was accepted as 0 and later used as the divisor in in_place_shift_memory(), a division by zero.

This rejects it with DETOOLS_CORRUPT_PATCH when the header is read, next to the existing to_size check.

This is the segment size check from #19 by @jmecom, split out on its own, since the review there asked for small separate PRs. The test is the same 6-byte patch, run through a small in-memory test_one_in_place() helper added to c/tst/test_fuzzer.c, beside test_one().

Without the fix, the new test fails under the suite's UBSan with detools.c:1672: runtime error: division by zero.

A segment size of 0 was accepted from the patch header and later used
as the divisor in in_place_shift_memory(), a division by zero.

Split out of eerimoq#19.
deadcaf3 added a commit to ultrawidelock/tinyfota that referenced this pull request Oct 21, 2026
- tests/powercut/powercut.c cuts the power at every flash operation of a
  real update between two sample builds (fixtures/), both lost and torn,
  then reboots twice. Every one of the 6,526 runs must end on the target
  image or on the untouched base. `make powercut`.
- tests/fuzz/: libFuzzer targets for the header parsers, the receiver's
  frame and SMP upload paths, and patch application, with seeds from
  gen_seeds.py. `make fuzz` builds them, `make fuzz-run` runs each for
  FUZZ_SECONDS.

Two applier defects the simulator found, fixed in core/dfu_applier.c and
pinned by new cases in tests/host/test_tinyfota.c:

- A read-back padded the write buffer's partial word out to flash, so the
  next write started mid-word and the nRF driver refused it, failing the
  patch with the slot half rewritten. Whole words are flushed now and the
  tail is overlaid on the read; a region that starts mid-word is written
  from the word boundary with 0xff lead bytes.
- A step reached the step log before the buffered bytes it covers were in
  flash, so a cut between the two resumed past bytes that never landed.
  The same held for the final clear. Both now flush first.

Two vendored detools crashes the fuzzers found on a corrupt patch, fixed
in third_party/detools/ and sent upstream (THIRD_PARTY.md):

- segment size 0 divided by zero (eerimoq/detools#20);
- the in-place from offset could overflow an int or reach mem_read()
  outside the memory (eerimoq/detools#21).

All 372 saved crash inputs replay clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant