mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(apple): read LC_LAZY_LOAD_DYLIB_INFO dependency payloads (#5650)
* fix(apple): read LC_LAZY_LOAD_DYLIB_INFO dependency payloads Parse the linkedit install name for lazy-load info commands, resolve those edges without traversing them, and stop inspect-macho from treating an otool dependency list as exhaustive when that payload is omitted. Fixes #5551 Fixes #5649 Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): bound lazy-load payload reads and image offsets Reuse identical LC_LAZY_LOAD_DYLIB_INFO ranges, cap their combined size, and reject flag or chain-start offsets outside the slice VM range. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): bound lazy-load string scans and contained reads Reject payload strings that start in the 24-byte header, validate each file-offset string once, and reuse payload bytes already read for a containing range. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): reject cached lazy-load strings outside a payload Remember each cached string's terminating offset and require that NUL to fall inside the payload being decoded. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): bound lazy-load payload range lookups Count containment checks across earlier payload reads and stop at the existing 16 MiB work limit. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): count every lazy-info string reference Charge repeated and overlapping LC_LAZY_LOAD_DYLIB_INFO scans against the 16 MiB validation budget, and stop a scan once that budget is exhausted. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): cap retained lazy-info dependency results Stop after 1024 LC_LAZY_LOAD_DYLIB_INFO commands so a load-command region full of identical commands cannot become a million traced edges. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): reject a lazy-load path NUL in the final byte dyld stops the load-path scan before the payload's last byte, so a terminator in that byte leaves the image malformed. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): keep may-be-missing lazy loads optional A missing LC_LAZY_LOAD_DYLIB_INFO with the may-be-missing bit is weak, so the lazy finding says dyld continues on first use instead of failing. Co-authored-by: morluto <morluto@users.noreply.github.com> * fix(apple): cap lazy-info symbol string references A payload of distinct one-byte symbol strings stayed under the byte budgets while caching one entry per offset. A slice now stops at 65536 symbol references. Co-authored-by: morluto <morluto@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: morluto <morluto@users.noreply.github.com>
This commit is contained in:
12 files changed
+1492
-23
No files matched your search
@@ -180,8 +180,21 @@ rea trace-dylib-resolution MyApp.app --root Contents/MacOS/MyApp --architecture
|
||||
|
||||
Load commands are parsed in TypeScript from Mach-O and FAT headers, including
|
||||
the `dylib_use_command` encoding newer linkers emit for flags such as delayed
|
||||
initialization. Nothing is executed and no Apple tool is required, so the tool
|
||||
also works off macOS.
|
||||
initialization, and `LC_LAZY_LOAD_DYLIB_INFO` (`0x3a`). That command stores its
|
||||
install name in a linkedit payload rather than in the load command itself.
|
||||
Its flag and chain-start image offsets must lie in the slice VM range, which
|
||||
is dyld's one-page floor extended by every segment except `__LINKEDIT`,
|
||||
measured from the `__TEXT` vmaddr. Payload strings must start after the 24-byte
|
||||
header. The load-path NUL must occur before the payload's final byte, matching
|
||||
dyld's scan. Distinct payload bytes and payload-range lookups stay within the 16 MiB
|
||||
limit, and a file range already read is reused. String scanning and UTF-8
|
||||
checks count every reference, including repeats and overlaps, and stop at that
|
||||
same aggregate. A slice retains at most 1024 of these commands; further copies are
|
||||
unsupported instead of becoming one traced edge each. Symbol references,
|
||||
including repeats, stop at 65536 per slice. A larger table is unsupported
|
||||
instead of caching one string per offset.
|
||||
Nothing is executed and no Apple tool is required, so the tool also works off
|
||||
macOS.
|
||||
|
||||
Resolution follows dyld:
|
||||
|
||||
@@ -222,8 +235,12 @@ cache rather than on disk, so REA does not check them against the host.
|
||||
`findings` are derived, not observed:
|
||||
|
||||
- `required-load-unresolved`, `weak-load-unresolved`, and `lazy-load-unresolved`.
|
||||
`LC_LAZY_LOAD_DYLIB` dependencies are resolved but not traversed, because dyld
|
||||
loads them on first use; an unresolved one is not a launch failure.
|
||||
`LC_LAZY_LOAD_DYLIB` and `LC_LAZY_LOAD_DYLIB_INFO` dependencies are resolved
|
||||
but not traversed, because dyld loads them on first use; an unresolved one is
|
||||
not a launch failure. `LC_LAZY_LOAD_DYLIB_INFO` has no compatibility version,
|
||||
so those fields are null. Its may-be-missing flag is reported as `weak`, and
|
||||
an unresolved dependency with that flag is not a first-use failure: dyld
|
||||
continues if the image is absent.
|
||||
- `earlier-rpath-candidate-absent`: a compatible Mach-O placed at an earlier
|
||||
modeled search path could take precedence, subject to unmodeled search inputs
|
||||
and code-signing library validation. These findings do not establish which
|
||||
|
||||
Reference in new issue
Block a user