Skip to content

Add a libopencm3 Cortex-M image with a string at the end of .text - #194

Open
zardus wants to merge 2 commits into
masterfrom
feature/cfgfast-string-boundary
Open

Add a libopencm3 Cortex-M image with a string at the end of .text#194
zardus wants to merge 2 commits into
masterfrom
feature/cfgfast-string-boundary

Conversation

@zardus

@zardus zardus commented Aug 25, 2026

Copy link
Copy Markdown
Member

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Problem

The linked angr change fixes CFGFast._scan_for_printable_strings claiming a NUL terminator it never saw, when a printable run reaches the end of the region being scanned. Reproducing that needs a string that ends exactly at a region boundary with a different section immediately after, and nothing here has that shape — the census in the validation record is 881 string classifications across the armel, armhf, m68k and aarch64 fixtures, none of them changed by the fix, from a detector that fires four times elsewhere in the same run. So the consumer's reproducer is a path that does not exist:

CLEFileNotFoundError: Could not find file binaries/tests/armel/libopencm3_adc-dac-printf.elf

Root cause

Most builds pad, so the layout is rare. tests/armel/libopencm3_adc-dac-printf.elf has it. Read back through cle.Loader:

<ELF Object libopencm3_adc-dac-printf.elf, maps [0x8000000:0x2000083b]>   arch=ARMCortexM
.text        vaddr=0x08000000 memsize=0x07484 end=0x08007484
.ARM.exidx   vaddr=0x08007484 memsize=0x00008 end=0x0800748c
'blanks.1'   0x8007464 size=16 type=SymbolType.TYPE_OBJECT
'zeroes.0'   0x8007474 size=16 type=SymbolType.TYPE_OBJECT

newlib's blanks[16] and zeroes[16] are the last 32 bytes of .text, and .ARM.exidx starts at the next byte with no gap.

Fix

Commit that image. It is the DecBench O2-noinline build of the libopencm3 adc-dac-printf example with DWARF removed by arm-none-eabi-strip --strip-debug, which takes it from 516 KB to 54 KB; the symbol table is kept so tests can name functions. Upstream is the BSD-2-Clause DecBench dataset at binaries/O2-noinline/libopencm3/adc-dac-printf.elf, built from LGPL-3.0-or-later libopencm3 sources, and the file was scanned for build paths and usernames before committing.

With the fixture present, p.analyses.CFGFast(data_references=True, normalize=True) on unfixed angr shows the defect the consumer repairs:

0x8007464 size=33 sort=string   content=b'                0000000000000000\xcc'
0x8007474 size=16 sort=string   content=b'0000000000000000'
0x8007484 size=1  sort=unknown  content=None
0x8007485 size=7  sort=unknown  content=None

The 33-byte string has swallowed the first byte of .ARM.exidx, and .ARM.exidx comes back as a 1-byte object plus a 7-byte object instead of one 8-byte object.

Testing

No test suite in this repository covers fixtures, so nothing is executed here. What was checked instead: the committed file loads through cle.Loader with the section and symbol addresses above, and the string measurement is identical before and after the strip — the same 471 scan calls, 23 of them non-zero, and the same single affected address with the same content — so stripping did not move the boundary the fixture exists to exercise.

Validation: #194 (comment)

sync: angr/angr#6943

session: sharpen

@zardus

zardus commented Aug 26, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Validation record for head 139420a09abf1b6448130da01aadee944d8c3699 against baseline a87538bc248531d2a1d22434143e8b9752459bac.

  • Exact PR shape: the own-merge-base/head scan verifies the added compiler-produced fixture and its load-bearing format/address shape: ARM EABI ELF; the unterminated string starts at 0x8007464 and reaches the .ARM.exidx boundary at 0x8007484.
  • Provenance/reproduction: ARM GNU Binutils 2.46 strip --strip-debug was rerun twice in separate fresh directories; both outputs byte-compare with each other and with the committed bytes.
  • Input/native identity: committed SHA-256 b38cee63084397c5dd6462d5ce732aaf1e6288980133aa7ea6d87589189d8679; isolated consumer-worktree rustylib artifact on both arms, SHA-256 0d9a42e9635de82f26b2c25d96d600ee8ca7e970cc7c5afb57deadcc5e9e2dfc (the structural harness did not record /proc/self/maps, so this is not claimed as a maps-derived identity).
  • Real consumer: CFGFast: Stop reporting a null terminator the string scan never saw angr#6943 at baseline 84684e2a72c4cb2261d9421873d9fdab58de82bb and head 1240c3fe3cb5e0d4d4c4646ca0f6144afdc74835 loaded the committed fixture and produced the complete output linked in this PR's output record.
  • Repeat/order control: A/B/B/A, a static structural/native capture whose determinism is established by separate same-arm processes; same-arm output is byte-identical and the cross-arm delta is nonempty.
  • Local scope: this recapture validates fixture bytes, fixture shape, and the actual consumer path only. It does not claim a fresh full-workspace gate.
  • Hosted status: fresh hosted dependency validation for this exact binaries head has not been observed in this recapture; it remains pending and no hosted success is claimed here.

@zardus

zardus commented Aug 28, 2026

Copy link
Copy Markdown
Member Author

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

Exact fixture-shape and consumer-output record for #194.

  • Fixture comparison: own merge base a87538bc248531d2a1d22434143e8b9752459bac versus exact head 139420a09abf1b6448130da01aadee944d8c3699. The target path/shape is absent on the merge base and present on the head. ARM EABI ELF; the unterminated string starts at 0x8007464 and reaches the .ARM.exidx boundary at 0x8007484.
  • Fixture identity: SHA-256 b38cee63084397c5dd6462d5ce732aaf1e6288980133aa7ea6d87589189d8679; source provenance: DecBench revision e5eb576d66ee36793b800a4dd45e291e0add4472, O2-noinline/libopencm3/adc-dac-printf.elf. The complete readelf/objdump scan is retained with the exact script. The recorded recipe (ARM GNU Binutils 2.46 strip --strip-debug) was rerun twice in fresh directories; both runs are byte-identical to the committed fixture.
  • Actual consumer: CFGFast: Stop reporting a null terminator the string scan never saw angr#6943, exact baseline 84684e2a72c4cb2261d9421873d9fdab58de82bb versus exact head 1240c3fe3cb5e0d4d4c4646ca0f6144afdc74835; target CFG memory-data record at 0x8007464; configuration CFGFast(normalize=True, data_references=True).
  • Native identity: isolated consumer-worktree rustylib artifact on both arms, SHA-256 0d9a42e9635de82f26b2c25d96d600ee8ca7e970cc7c5afb57deadcc5e9e2dfc (the structural harness did not record /proc/self/maps, so this is not claimed as a maps-derived identity).
  • Determinism: fresh A/B/B/A order, a static structural/native capture whose determinism is established by separate same-arm processes; each same-arm pair is byte-identical and every base/head comparison below is nonempty. Absolute checkout prefixes in tracebacks are normalized to <workspace> for publication; raw output is retained unchanged.

Before — CFG memory-data record at 0x8007464

Exact consumer baseline
address=0x8007464
size=33
sort=string
content=b'                0000000000000000\xcc'

After — CFG memory-data record at 0x8007464

Exact consumer head
address=0x8007464
size=32
sort=string
content=b'                0000000000000000'

tests/armel/libopencm3_adc-dac-printf.elf is the DecBench O2-noinline build of
the libopencm3 adc-dac-printf example, with DWARF removed (arm-none-eabi-strip
--strip-debug, 516 KB -> 54 KB); the symbol table is kept so tests can name
functions.

Its newlib blanks[16]+zeroes[16] pair occupies the last 32 bytes of .text, which
ends at 0x8007484 where .ARM.exidx begins. That layout is what CFGFast's
printable-string scan needs in order to run off the end of a region, so angr uses
it to pin the recovered string to the region rather than one byte past it.

Upstream: https://huggingface.co/datasets/noelo-lab/decbench-dataset
binaries/O2-noinline/libopencm3/adc-dac-printf.elf (BSD-2-Clause dataset,
libopencm3 sources are LGPL-3.0-or-later).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@zardus
zardus force-pushed the feature/cfgfast-string-boundary branch from 9651e43 to 139420a Compare August 28, 2026 16:47
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