Several DyldCache / FullDyldCache accessors trap (try!, precondition, arithmetic overflow, numericCast) when header values are out of range, instead of returning nil. A viewer or tool that opens untrusted caches crashes before it can report anything.
| Accessor |
Location |
Trap |
DyldCache.init(url:) |
DyldCache.swift:87 |
try! fileHandle.read(offset: 0) on a file shorter than dyld_cache_header |
imageInfos, imageTextInfos |
DyldCache.swift:223, :232 |
readDataSequence with the declared count; try! in swift-fileio-extra (_FileIOProtocol+.swift:36) when the array runs past EOF |
slide info pageStarts / pageExtras / toc (v1–v5) |
Model/DyldCache/SlideInfo/* |
same readDataSequence path with untrusted page_starts_count, page_extras_count, toc_count |
codeSign |
DyldCache.swift:365 |
numericCast of codeSignatureSize to Int, then try! fileSlice(...) |
expectedCacheFileSize |
Protocol/DyldCacheRepresentable.swift:173 |
map.fileOffset + map.size + header.codeSignatureSize overflows |
fileOffset(of:) |
Protocol/DyldCacheRepresentable.swift:182 |
address - mapping.address + mapping.fileOffset can overflow with a malformed fileOffset |
Reproduce
- A 16-byte file
"dyld_v1 arm64e\0" → DyldCache(url:) traps.
- A copy of a real main cache file with any of these changes:
imagesCount = 0xFFFFFFFF → imageInfos traps.
imagesTextCount = UInt64.max / 2 → imageTextInfos traps.
codeSignatureSize = UInt64.max → codeSign and expectedCacheFileSize trap.
Suggestion
- Throw from
init(url:) when the header cannot be read. It already throws.
- Validate
offset + count * size against the file size (using checked arithmetic) before readDataSequence, and return nil otherwise. A throwing / optional readDataSequence in swift-fileio-extra would fix every caller at once.
- Use
addingReportingOverflow for the range sums above.
Callers can currently only work around these by bounds-checking before each call.
Several
DyldCache/FullDyldCacheaccessors trap (try!, precondition, arithmetic overflow,numericCast) when header values are out of range, instead of returningnil. A viewer or tool that opens untrusted caches crashes before it can report anything.DyldCache.init(url:)DyldCache.swift:87try! fileHandle.read(offset: 0)on a file shorter thandyld_cache_headerimageInfos,imageTextInfosDyldCache.swift:223,:232readDataSequencewith the declared count;try!inswift-fileio-extra(_FileIOProtocol+.swift:36) when the array runs past EOFpageStarts/pageExtras/toc(v1–v5)Model/DyldCache/SlideInfo/*readDataSequencepath with untrustedpage_starts_count,page_extras_count,toc_countcodeSignDyldCache.swift:365numericCastofcodeSignatureSizetoInt, thentry! fileSlice(...)expectedCacheFileSizeProtocol/DyldCacheRepresentable.swift:173map.fileOffset + map.size + header.codeSignatureSizeoverflowsfileOffset(of:)Protocol/DyldCacheRepresentable.swift:182address - mapping.address + mapping.fileOffsetcan overflow with a malformedfileOffsetReproduce
"dyld_v1 arm64e\0"→DyldCache(url:)traps.imagesCount = 0xFFFFFFFF→imageInfostraps.imagesTextCount = UInt64.max / 2→imageTextInfostraps.codeSignatureSize = UInt64.max→codeSignandexpectedCacheFileSizetrap.Suggestion
init(url:)when the header cannot be read. It alreadythrows.offset + count * sizeagainst the file size (using checked arithmetic) beforereadDataSequence, and returnnilotherwise. A throwing / optionalreadDataSequenceinswift-fileio-extrawould fix every caller at once.addingReportingOverflowfor the range sums above.Callers can currently only work around these by bounds-checking before each call.