fix(apple): map Intel version-min to simulators; fail truncated cache hashes
This commit is contained in:
@@ -552,18 +552,31 @@ export class DyldSharedCache {
|
||||
): Promise<string> {
|
||||
const hash = createHash("sha256");
|
||||
const buffer = Buffer.alloc(HASH_CHUNK_BYTES);
|
||||
for (let position = 0; position < file.size;) {
|
||||
let position = 0;
|
||||
for (;;) {
|
||||
signal?.throwIfAborted();
|
||||
if (position >= file.size) break;
|
||||
const { bytesRead } = await file.handle.read(
|
||||
buffer,
|
||||
0,
|
||||
Math.min(buffer.length, file.size - position),
|
||||
position,
|
||||
);
|
||||
if (bytesRead === 0) break;
|
||||
// A file truncated after open must not yield the surviving prefix's
|
||||
// digest as the identity of the recorded size.
|
||||
if (bytesRead === 0)
|
||||
throw new ArtifactReaderFailure(
|
||||
"integrity",
|
||||
"dyld cache file changed while its digest was read",
|
||||
);
|
||||
hash.update(buffer.subarray(0, bytesRead));
|
||||
position += bytesRead;
|
||||
}
|
||||
if (position !== file.size)
|
||||
throw new ArtifactReaderFailure(
|
||||
"integrity",
|
||||
"dyld cache file changed while its digest was read",
|
||||
);
|
||||
return hash.digest("hex");
|
||||
}
|
||||
|
||||
|
||||
@@ -186,6 +186,13 @@ describe("Mach-O load command reader inputs", () => {
|
||||
{ id: 2, name: "ios" },
|
||||
{ id: 99, name: null },
|
||||
]);
|
||||
// Legacy version-min commands on Intel slices denote simulators.
|
||||
const intel = await read(
|
||||
machoImage({ cpu: CPU.x86_64, commands: [versionMin] }),
|
||||
);
|
||||
expect(intel.status === "parsed" && intel.slices[0]?.platforms).toEqual([
|
||||
{ id: 7, name: "ios-simulator" },
|
||||
]);
|
||||
// A 16-byte LC_BUILD_VERSION, and one that declares a tool it lacks.
|
||||
const truncated = buildVersionCommand(1).slice(0, 16);
|
||||
new DataView(truncated.buffer).setUint32(4, 16, true);
|
||||
|
||||
@@ -268,7 +268,7 @@ const decodeCommands = (
|
||||
`load command ${index} at offset ${offset} has invalid cmdsize ${size}`,
|
||||
);
|
||||
const body = bytes.subarray(offset, offset + size);
|
||||
decodeCommand(command, body, index, slice);
|
||||
decodeCommand(command, body, index, slice, header.cpuType);
|
||||
offset += size;
|
||||
}
|
||||
// A header that declares fewer commands than its sizeofcmds could hide
|
||||
@@ -286,6 +286,7 @@ const decodeCommand = (
|
||||
body: Uint8Array,
|
||||
index: number,
|
||||
slice: MachoSlice,
|
||||
cpuType: number,
|
||||
): void => {
|
||||
if (command === LC_ID_DYLIB) {
|
||||
slice.install_name = commandString(body, 24, index);
|
||||
@@ -324,7 +325,20 @@ const decodeCommand = (
|
||||
"malformed",
|
||||
`load command ${index} is too short for a platform version`,
|
||||
);
|
||||
const id = implied ?? viewOf(body).getUint32(8, true);
|
||||
const declared = implied ?? viewOf(body).getUint32(8, true);
|
||||
// Legacy LC_VERSION_MIN_* commands on Intel slices denote simulator
|
||||
// platforms; Apple's decoder branches on the CPU type for these commands.
|
||||
const intel = cpuType === 7 || cpuType === (7 | 0x01000000);
|
||||
const id =
|
||||
implied !== undefined && intel
|
||||
? declared === 2
|
||||
? 7
|
||||
: declared === 3
|
||||
? 8
|
||||
: declared === 4
|
||||
? 9
|
||||
: declared
|
||||
: declared;
|
||||
if (!slice.platforms.some((platform) => platform.id === id))
|
||||
slice.platforms.push(applePlatform(id));
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user