Files
rea/tests/boundary/filesystem/machoCommandAdmission.test.ts
T

153 lines
5.2 KiB
TypeScript

import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import { parseBinaryTarget } from "../../../src/application/BinaryTargetResolver.js";
import { thinMach } from "../../../src/domain/binaryTarget.fixture.js";
import { parseExecutableHeader } from "../../../src/domain/binaryTarget.js";
import { projectAnalysisError } from "../../../src/domain/analysisErrorProjection.js";
import { BinaryTargetError } from "../../../src/domain/configurationErrors.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import {
CPU,
fatImage,
} from "../../../src/artifacts/apple/MachoImage.fixture.js";
const commandImage = (
wide: boolean,
littleEndian: boolean,
sizes: readonly number[],
): Buffer => {
const magic = wide
? littleEndian
? 0xcffaedfe
: 0xfeedfacf
: littleEndian
? 0xcefaedfe
: 0xfeedface;
const header = thinMach(magic, wide ? 0x0100000c : 7);
const bytes = Buffer.alloc(
header.length + sizes.reduce((total, size) => total + size, 0),
);
header.copy(bytes);
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
view.setUint32(16, sizes.length, littleEndian);
view.setUint32(20, bytes.length - header.length, littleEndian);
let offset = header.length;
for (const size of sizes) {
view.setUint32(offset, 0x7fffffff, littleEndian); // Unknown commands still have framing.
view.setUint32(offset + 4, size, littleEndian);
offset += size;
}
return bytes;
};
it.each([
{ label: "undersized", field: 36, value: 4 },
{ label: "unaligned", field: 36, value: 12 },
{ label: "outside table", field: 36, value: 0xffffffff },
{ label: "too many commands", field: 16, value: 2 },
{ label: "unclaimed table bytes", field: 16, value: 0 },
{ label: "trailing table bytes", field: 36, value: 8 },
])(
"rejects $label thin command framing before provider admission",
async ({ field, value }) => {
const bytes = commandImage(true, true, [16]);
bytes.writeUInt32LE(value, field);
const path = join(
await createTestTempDirectory("rea-macho-command-"),
"image",
);
await writeFile(path, bytes);
expect(parseExecutableHeader(bytes, "arm64").ok).toBe(false);
const resolved = await parseBinaryTarget(path);
expect(resolved.ok).toBe(false);
if (resolved.ok || !(resolved.error instanceof BinaryTargetError))
throw new Error("Expected target format refusal");
expect(projectAnalysisError(resolved.error)).toMatchObject({
code: "target_unavailable",
category: "unsupported_target",
});
expect(resolved.error.reason).toMatch(/load command/iu);
},
);
it.each([
{ wide: false, littleEndian: false, size: 12 },
{ wide: false, littleEndian: true, size: 12 },
{ wide: true, littleEndian: false, size: 16 },
{ wide: true, littleEndian: true, size: 16 },
])(
"retains width-specific alignment and endian controls ($wide/$littleEndian)",
async ({ wide, littleEndian, size }) => {
const bytes = commandImage(wide, littleEndian, [size]);
const path = join(
await createTestTempDirectory("rea-macho-command-control-"),
"image",
);
await writeFile(path, bytes);
expect(await parseBinaryTarget(path)).toMatchObject({
ok: true,
value: { format: "mach-o", architecture: wide ? "arm64" : "x86" },
});
},
);
it.each([false, true])(
"walks command headers beyond the probe window (corrupt=%s)",
async (corrupt) => {
const bytes = commandImage(true, true, [4104, 16]);
if (corrupt) bytes.writeUInt32LE(0xffffffff, 32 + 4104 + 4);
const path = join(
await createTestTempDirectory("rea-macho-command-window-"),
"image",
);
await writeFile(path, bytes);
const resolved = await parseBinaryTarget(path);
expect(resolved.ok).toBe(!corrupt);
if (!resolved.ok) {
if (!(resolved.error instanceof BinaryTargetError)) throw resolved.error;
expect(resolved.error.reason).toContain("load command 1");
}
},
);
it.each([null, 0, 1])(
"checks every admitted FAT slice's framing (corrupt slice %s)",
async (corruptIndex) => {
const slices = [
commandImage(true, true, [16]),
commandImage(true, true, [16]),
];
const x86 = slices[0]!;
x86.writeUInt32LE(CPU.x86_64.type, 4);
x86.writeUInt32LE(CPU.x86_64.subtype, 8);
if (corruptIndex !== null)
slices[corruptIndex]!.writeUInt32LE(0xffffffff, 36);
const bytes = fatImage([
{ cpu: CPU.x86_64, bytes: x86 },
{ cpu: CPU.arm64, bytes: slices[1]! },
]);
const path = join(
await createTestTempDirectory("rea-fat-command-"),
"image",
);
await writeFile(path, bytes);
const resolved = await parseBinaryTarget(path, {
hostArchitecture: "arm64",
});
expect(resolved.ok).toBe(corruptIndex === null);
if (!resolved.ok) {
if (!(resolved.error instanceof BinaryTargetError)) throw resolved.error;
expect(resolved.error.reason).toContain("invalid cmdsize");
expect(projectAnalysisError(resolved.error)).toMatchObject({
code: "target_unavailable",
});
} else
expect(resolved.value).toMatchObject({
format: "mach-o-universal",
architecture: "arm64",
});
},
);