fix(native): preserve negative Mach-O admission identity

This commit is contained in:
morluto committed 2026-10-24 02:50:17 +08:00
1 parent 787726817c
commit c20b707680
4 files changed
+31 -4

No files matched your search

+7
View File
@@ -346,6 +346,13 @@ Mach-O fixtures check each case against source-owned return values.
## Static inspection
Native target admission checks Mach-O slice headers before assigning FAT
identity. A shared `CAFEBABE` prefix whose declarations do not identify Mach-O
images receives the generic unsupported-format refusal, including JVM class
files larger than the bounded admission probe. This does not identify a partial
prefix as a validated JVM class. Malformed recognized FAT declarations retain
their format-specific reasons.
`inspect_artifact` and `extract_artifact` retain universal Mach-O slices under
their exact `lipo` names, including 32-bit ARM implementations such as `armv7`,
`armv7s`, and `armv7k`. These names are reconciled with the FAT CPU subtype;
+2 -2
View File
@@ -43,7 +43,7 @@ describe("FAT Mach-O identity", () => {
});
expect(parseExecutableHeader(Buffer.from(bytes), "arm64")).toEqual({
ok: false,
error: "FAT table does not identify a Mach-O image",
error: "unsupported binary format",
});
});
@@ -62,7 +62,7 @@ describe("FAT Mach-O identity", () => {
});
expect(parseExecutableHeader(Buffer.from(bytes), "arm64")).toEqual({
ok: false,
error: "FAT table does not identify a Mach-O image",
error: "unsupported binary format",
});
});
+1 -2
View File
@@ -373,8 +373,7 @@ const fatIdentityError = (
});
if (identity.state === "needs-slice-header")
return "FAT slice identity is outside the bounded prefix";
if (identity.state === "not-mach-o")
return "FAT table does not identify a Mach-O image";
if (identity.state === "not-mach-o") return "unsupported binary format";
if (identity.state === "malformed") return identity.reason;
return null;
};
@@ -31,6 +31,7 @@ import { hasXmlPlistSignature } from "../../../src/domain/apple/appleArchiveForm
import { parseExecutableHeader } from "../../../src/domain/binaryTarget.js";
import { createEvidence, parseEvidence } from "../../../src/domain/evidence.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { javaClassFile } from "../../fixtures/javaClassFile.js";
import {
arArchive,
CPU,
@@ -38,6 +39,26 @@ import {
machoImage,
} from "../../../src/artifacts/apple/MachoImage.fixture.js";
it.each([4000, 9000])(
"refuses a JVM class with %i unused constant bytes without claiming FAT identity",
async (constantBytes) => {
const directory = await createTestTempDirectory("rea-class-target-");
const path = join(directory, "input.class");
await writeFile(path, javaClassFile(constantBytes));
const resolved = await parseBinaryTarget(path);
expect(resolved).toMatchObject({
ok: false,
error: { reason: "unsupported binary format" },
});
if (resolved.ok) throw new Error("JVM class was admitted as executable");
expect(projectAnalysisError(resolved.error)).toMatchObject({
code: "target_unavailable",
category: "unsupported_target",
details: { reason: "unsupported binary format" },
});
},
);
it.each([0x01c0, 0x01c2, 0x01c4, 0xaa64])(
"retains original PE COFF machine %i through file-backed target resolution",
async (peMachine) => {