Conversation
When a parent backer runs past either end of the view's window, backers() takes a memoryview of it and clamps. Both halves of that arithmetic are wrong. clamp_end should be self._endoffset - taddr, the offset inside the backer where the window ends. It is written as len(backer) minus that, so it coincides with the right answer only when len(backer) is exactly twice it. A 256-address view over fauxware's 2676-byte first backer yielded 2420 bytes, so a view can hand out an order of magnitude more memory than it covers. The else arm beside it, taken when the backer does not overrun the window, was already right. The address yielded is taddr, where the parent backer starts in the view, and not where the clamped slice starts. It is short by whatever the low end was clamped by, so it can fall below the view's own _offset -- and where taddr is itself negative, because the parent backer begins below _rebase, so is the address the view reports: ClemoryView(memory, 0x400010, 0x400100) reports its backer at -0x10. Take the intersection of the backer and the window in the backer's own offsets, and yield the address the slice begins at. The fully-contained and fully-outside branches above are unchanged, so a backer that needs no clamping is still handed out as itself rather than as a memoryview.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head
Caller survey:
Merge state, measured on the committed head against every open pull request that touches Caveats: the workspace-wide gate was not run — this machine's native libraries are pinned by running corpus sweeps and rebuilding them is forbidden — so validation is the cle suite, the two CI diff checks and the survey above. No corpus A/B: with no caller in any of the three repositories, a sweep has nothing to move. |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS What Before — every window reports a length that is not its own, and two report angr/cle master 0e77ade>>> [(hex(s), len(b)) for s, b in cle.ClemoryView(memory, 0x400000, 0x400100).backers()]
[('0x0', 2420)]
>>> [(hex(s), len(b)) for s, b in cle.ClemoryView(memory, 0x400010, 0x400100).backers()]
[('-0x10', 2404)]
>>> [(hex(s), len(b)) for s, b in cle.ClemoryView(memory, 0x600e30, 0x600e40, offset=0x10).backers()]
[('0x8', 536)]
>>> view = cle.ClemoryView(memory, 0x600e30, 0x600e40, offset=0x10)
>>> [view.load(s, len(b)) for s, b in view.backers()]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "cle/memory.py", line 589, in load
raise KeyError(addr)
KeyError: 8After — each window reports its own length, at an address inside itself, and with this change>>> [(hex(s), len(b)) for s, b in cle.ClemoryView(memory, 0x400000, 0x400100).backers()]
[('0x0', 256)]
>>> [(hex(s), len(b)) for s, b in cle.ClemoryView(memory, 0x400010, 0x400100).backers()]
[('0x0', 240)]
>>> [(hex(s), len(b)) for s, b in cle.ClemoryView(memory, 0x600e30, 0x600e40, offset=0x10).backers()]
[('0x10', 16)]
>>> view = cle.ClemoryView(memory, 0x600e30, 0x600e40, offset=0x10)
>>> [bytes(b) == view.load(s, len(b)) for s, b in view.backers()]
[True] |
|
Corpus decompilation diffs can be found at angr/dec-snapshots@master...angr/cle_823 |
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
ClemoryView.backers()hands out the wrong slice, at the wrong address,whenever a parent backer runs past either end of the view's window. On
binaries/tests/x86_64/fauxware, loaded withauto_load_libs=False:A view covering 256 addresses reports 2420 bytes of them. A view whose window
starts 0x10 into a parent backer reports that backer at a negative address. A
view with an offset of its own reports a 16-address window as 536 bytes at
0x8, which is below the view's own_offset, soview.load(0x8, 536)raisesKeyErroron the very backer the view just handed out.Root cause
Both halves of the clamp are wrong.
self._endoffset - taddris the offset inside the backer where the window ends,and that is what
clamp_endshould be. The expression islen(backer)minusthat. The two coincide only when
len(backer)is exactly twiceself._endoffset - taddr, which is a coincidence and not a case. Theelsearmbelow it, taken when the backer does not overrun the window, is already right.
taddris where the parent backer starts in the view's address space. The slicestarts
clamp_startbytes later than that, so the address is short by exactlythe amount the low end was clamped by. Where
taddris itself negative, becausethe parent backer begins below
self._rebase, so is the address the viewreports.
Fix
Take the intersection of the backer and the window in the backer's own offsets,
and yield the address the slice really begins at.
The two branches above it are untouched, so a backer that lies wholly inside the
window is still yielded as itself rather than as a
memoryview, and one whollyoutside is still skipped.
Testing
test_clemory_view_backers_are_clamped_to_the_windowloads fauxware and assertsthe address and the length of what two differently clamped windows hand out
against the window's own bounds, and their bytes against what the parent
Clemoryreturns for the same range. It fails on master at the first assertion,with
(0, 2420)where(0, 256)is expected.Validation: #823 (comment)
session: sharpen