mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 00:36:35 +00:00
fix(native): preserve unknown ARM64 subtype in hardening (#9600)
This commit is contained in:
1 parent
897caa814d
commit
cc13c5d095
3 files changed
+81
-9
No files matched your search
@@ -5,6 +5,24 @@ const CPU_SUBTYPE_CAPABILITY_MASK = 0xff000000;
|
||||
export const machoCpuSubtypeBase = (cpuSubtype: number): number =>
|
||||
cpuSubtype & ~CPU_SUBTYPE_CAPABILITY_MASK;
|
||||
|
||||
/** Known ARM64 subtype identity, distinct from the family display fallback. */
|
||||
export const machoKnownArm64Subtype = (
|
||||
cpuSubtype: number,
|
||||
): string | undefined => {
|
||||
switch (machoCpuSubtypeBase(cpuSubtype)) {
|
||||
case 0:
|
||||
return "arm64";
|
||||
case 1:
|
||||
return "arm64v8";
|
||||
case 2:
|
||||
return "arm64e";
|
||||
case 12:
|
||||
return "arm64e.x1";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Display known byte-header identities without inferring pointer-auth ABI names.
|
||||
* Subtype 12: llvm-project b8007a8e4020b8bca2b12e941660e10bf5bf6716,
|
||||
@@ -16,10 +34,7 @@ export const machoArchitectureName = (
|
||||
): string => {
|
||||
const subtype = machoCpuSubtypeBase(cpuSubtype);
|
||||
if (cpuType === 0x0100000c) {
|
||||
if (subtype === 12) return "arm64e.x1";
|
||||
if (subtype === 2) return "arm64e";
|
||||
if (subtype === 1) return "arm64v8";
|
||||
return "arm64";
|
||||
return machoKnownArm64Subtype(cpuSubtype) ?? "arm64";
|
||||
}
|
||||
if (cpuType === 0x0200000c) return "arm64_32";
|
||||
if (cpuType === 0x01000007) return subtype === 8 ? "x86_64h" : "x86_64";
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { validateFatSliceIdentity } from "../../domain/apple/machoContainer.js";
|
||||
import { machoArchitectureName } from "../../domain/apple/machoCpuIdentity.js";
|
||||
import {
|
||||
machoArchitectureName,
|
||||
machoKnownArm64Subtype,
|
||||
} from "../../domain/apple/machoCpuIdentity.js";
|
||||
import {
|
||||
MACHO_HEADER_FLAGS_OFFSET,
|
||||
readMachoLinkeditDataCommand,
|
||||
@@ -386,7 +389,6 @@ const buildRows = (
|
||||
flagLocation,
|
||||
);
|
||||
};
|
||||
const architecture = machoArchitectureName(header.cpuType, header.cpuSubtype);
|
||||
const pie =
|
||||
header.fileType === MH_DYLIB || header.fileType === MH_BUNDLE
|
||||
? row(
|
||||
@@ -435,7 +437,7 @@ const buildRows = (
|
||||
},
|
||||
),
|
||||
encryptionRow(encrypted),
|
||||
arm64Row(header.cpuType, architecture, ref.offset),
|
||||
arm64Row(header.cpuType, header.cpuSubtype, ref.offset),
|
||||
stackRow(bytes, ref, header.wide, symtab),
|
||||
row(
|
||||
"hardened_runtime",
|
||||
@@ -523,7 +525,7 @@ const encryptionRow = (encrypted: MachoSliceEncryption): BinaryHardeningRow => {
|
||||
|
||||
const arm64Row = (
|
||||
cpuType: number,
|
||||
architecture: string,
|
||||
cpuSubtype: number,
|
||||
sliceOffset: number,
|
||||
): BinaryHardeningRow => {
|
||||
const location = { offset: sliceOffset + 8, bytes: 4 };
|
||||
@@ -534,6 +536,14 @@ const arm64Row = (
|
||||
`CPU type 0x${cpuType.toString(16)} is not ARM64.`,
|
||||
location,
|
||||
);
|
||||
const architecture = machoKnownArm64Subtype(cpuSubtype);
|
||||
if (architecture === undefined)
|
||||
return row(
|
||||
"arm64e",
|
||||
"unknown",
|
||||
`Unrecognized ARM64 CPU subtype 0x${(cpuSubtype >>> 0).toString(16)}; arm64e status is unknown.`,
|
||||
{ offset: sliceOffset + 8, bytes: 4 },
|
||||
);
|
||||
const enabled = architecture === "arm64e" || architecture === "arm64e.x1";
|
||||
return row(
|
||||
"arm64e",
|
||||
|
||||
@@ -3,7 +3,10 @@ import { join } from "node:path";
|
||||
import { expect } from "vitest";
|
||||
import { toolContract } from "../../../src/contracts/toolContracts.js";
|
||||
import { createServer } from "../../../src/server/createServer.js";
|
||||
import { elfHardeningFixture } from "../../../src/native/hardening/BinaryHardening.fixture.js";
|
||||
import {
|
||||
elfHardeningFixture,
|
||||
machoHardeningFixture,
|
||||
} from "../../../src/native/hardening/BinaryHardening.fixture.js";
|
||||
import { createTestBinarySession } from "../../fixtures/binarySession.js";
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { mcpTest } from "../../support/mcp/mcpFixture.js";
|
||||
@@ -63,3 +66,47 @@ mcpTest(
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
|
||||
mcpTest(
|
||||
"reports an unknown ARM64 subtype without treating its display fallback as arm64e proof",
|
||||
async ({ mcp }) => {
|
||||
const session = createTestBinarySession(() => {
|
||||
throw new Error("Must not start a deep provider");
|
||||
});
|
||||
const client = await mcp.connect(
|
||||
createServer({ kind: "session", session }),
|
||||
);
|
||||
try {
|
||||
const root = await createTestTempDirectory("rea-arm64-subtype-");
|
||||
const path = join(root, "image");
|
||||
for (const [subtype, state] of [
|
||||
[0, "disabled"],
|
||||
[1, "disabled"],
|
||||
[2, "enabled"],
|
||||
[0x8000000c, "enabled"],
|
||||
[3, "unknown"],
|
||||
] as const) {
|
||||
const bytes = machoHardeningFixture({ cpuSubtype: subtype });
|
||||
await writeFile(path, bytes);
|
||||
const response = await client.callTool({
|
||||
name: "inspect_binary_hardening",
|
||||
arguments: { path },
|
||||
});
|
||||
expect(response.isError, JSON.stringify(response.content)).not.toBe(
|
||||
true,
|
||||
);
|
||||
const evidence = toolContract(
|
||||
"inspect_binary_hardening",
|
||||
).outputSchema.parse(response.structuredContent);
|
||||
const image = evidence.normalized_result.images[0];
|
||||
expect(image?.status).toBe("parsed");
|
||||
expect(
|
||||
image?.rows.find((row) => row.property === "arm64e")?.state,
|
||||
).toBe(state);
|
||||
}
|
||||
} finally {
|
||||
await session.close();
|
||||
}
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
Reference in new issue
Block a user