Merge pull request #1172 from morluto/fix/macho-arm64e-variant-slices
fix(artifacts): match lipo arm64e variant names to their FAT slices
This commit is contained in:
@@ -255,7 +255,7 @@ const lipoMatchesSlice = (
|
|||||||
reported.cpu_subtype_code !== null;
|
reported.cpu_subtype_code !== null;
|
||||||
return (
|
return (
|
||||||
(hasPhysicalIdentity || structurallyUnique) &&
|
(hasPhysicalIdentity || structurallyUnique) &&
|
||||||
reported.name === observed.architecture &&
|
lipoNameMatches(reported.name, observed.architecture) &&
|
||||||
(reported.file_offset === null ||
|
(reported.file_offset === null ||
|
||||||
reported.file_offset === observed.slice_offset) &&
|
reported.file_offset === observed.slice_offset) &&
|
||||||
(reported.size === null || reported.size === observed.slice_size) &&
|
(reported.size === null || reported.size === observed.slice_size) &&
|
||||||
@@ -269,6 +269,15 @@ const lipoMatchesSlice = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Newer lipo names an arm64e ABI variant `arm64e.<variant>` (for example
|
||||||
|
* `arm64e.v1` for pointer-auth ABI version 1). The FAT table names that slice
|
||||||
|
* `arm64e`; its physical identity is still compared field by field.
|
||||||
|
*/
|
||||||
|
const lipoNameMatches = (reported: string, observed: string): boolean =>
|
||||||
|
reported === observed ||
|
||||||
|
(observed === "arm64e" && /^arm64e\.[A-Za-z0-9_]+$/u.test(reported));
|
||||||
|
|
||||||
const parseSliceKeyInteger = (value: string | undefined): number | null => {
|
const parseSliceKeyInteger = (value: string | undefined): number | null => {
|
||||||
if (value === undefined || !/^\d+$/u.test(value)) return null;
|
if (value === undefined || !/^\d+$/u.test(value)) return null;
|
||||||
const parsed = Number(value);
|
const parsed = Number(value);
|
||||||
|
|||||||
@@ -186,3 +186,72 @@ const lipoRunner = (stdout: string): NativeCommandRunner => ({
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Newer lipo names arm64e ABI variants `arm64e.<variant>`; the FAT table names
|
||||||
|
// the same slice `arm64e`, and its physical identity must still match.
|
||||||
|
describe("artifact Mach-O arm64e variant slices", () => {
|
||||||
|
const ARM64E_V1 = { type: 0x0100000c, subtype: 0x81000002 } as const;
|
||||||
|
const variantSlices = async (
|
||||||
|
cpu: { readonly type: number; readonly subtype: number },
|
||||||
|
lipo: (size: number) => string,
|
||||||
|
) => {
|
||||||
|
const root = await createTestTempDirectory("rea-slices-arm64e-");
|
||||||
|
const binary = join(root, "fat");
|
||||||
|
const x86 = machoImage({ cpu: CPU.x86_64 });
|
||||||
|
const arm = machoImage({ cpu });
|
||||||
|
await writeFile(
|
||||||
|
binary,
|
||||||
|
fatImage([
|
||||||
|
{ cpu: CPU.x86_64, bytes: x86 },
|
||||||
|
{ cpu, bytes: arm },
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
const reader = new MachOSliceArtifactReader(
|
||||||
|
binary,
|
||||||
|
lipoRunner(
|
||||||
|
`architecture x86_64\n cputype CPU_TYPE_X86_64\n cpusubtype CPU_SUBTYPE_X86_64_ALL\n offset 4096\n size ${String(x86.length)}\n align 2^12 (4096)\n${lipo(arm.length)}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const entries = [];
|
||||||
|
for await (const entry of reader.entries()) entries.push(entry);
|
||||||
|
return entries.map(({ path, byteOffset }) => [path, byteOffset]);
|
||||||
|
};
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[
|
||||||
|
"arm64e.v1",
|
||||||
|
" cputype CPU_TYPE_ARM64\n cpusubtype CPU_SUBTYPE_ARM64E\n capabilities PTR_AUTH_VERSION USERSPACE 1",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"arm64e.x1",
|
||||||
|
" cputype CPU_TYPE_ARM64\n cpusubtype unknown arm64 cpusubtype",
|
||||||
|
],
|
||||||
|
])("accepts lipo's %s name for the FAT arm64e slice", async (name, cpu) => {
|
||||||
|
expect(
|
||||||
|
await variantSlices(
|
||||||
|
ARM64E_V1,
|
||||||
|
(size) =>
|
||||||
|
`architecture ${name}\n${cpu}\n offset 8192\n size ${String(size)}\n align 2^12 (4096)\n`,
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
["slices/x86_64", 4096],
|
||||||
|
[`slices/${name}`, 8192],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["a plain arm64 slice", CPU.arm64, "8192"],
|
||||||
|
["a different offset", ARM64E_V1, "8193"],
|
||||||
|
])(
|
||||||
|
"still rejects an arm64e variant name for %s",
|
||||||
|
async (_label, cpu, offset) => {
|
||||||
|
await expect(
|
||||||
|
variantSlices(
|
||||||
|
cpu,
|
||||||
|
(size) =>
|
||||||
|
`architecture arm64e.v1\n cputype CPU_TYPE_ARM64\n cpusubtype unknown arm64 cpusubtype\n offset ${offset}\n size ${String(size)}\n align 2^12 (4096)\n`,
|
||||||
|
),
|
||||||
|
).rejects.toMatchObject({ reason: "integrity" });
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user