mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
fix(elf): reuse recognized machine architecture facts
Preserve the shared EM_HEXAGON classification in Go and Rust image reports. Fixes #6629
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
type LoadRegion,
|
||||
type ZeroFillMapping,
|
||||
} from "./BinaryContainer.js";
|
||||
import { elfArchitecture } from "../../domain/elfFixedHeader.js";
|
||||
import { readNativeDirectoryFromBuffer } from "./NativeSectionDirectory.js";
|
||||
|
||||
/** Read ELF sections and file-backed program mappings without interpreting language metadata. */
|
||||
@@ -105,17 +106,27 @@ export const readElfImage = (bytes: Buffer): BinaryContainer => {
|
||||
|
||||
/** Map ELF machine identifiers to stable architecture names. */
|
||||
export const architectureForElfMachine = (machine: number): string => {
|
||||
const names = new Map([
|
||||
[3, "386"],
|
||||
[8, "mips"],
|
||||
[20, "ppc"],
|
||||
[21, "ppc64"],
|
||||
[22, "s390"],
|
||||
[40, "arm"],
|
||||
[62, "amd64"],
|
||||
[183, "arm64"],
|
||||
[243, "riscv"],
|
||||
[258, "loongarch"],
|
||||
]);
|
||||
return names.get(machine) ?? `elf-machine-${machine}`;
|
||||
const architecture = elfArchitecture(machine);
|
||||
if (architecture !== undefined) {
|
||||
switch (architecture) {
|
||||
case "x86":
|
||||
return "386";
|
||||
case "x86_64":
|
||||
return "amd64";
|
||||
case "powerpc":
|
||||
return "ppc";
|
||||
default:
|
||||
return architecture;
|
||||
}
|
||||
}
|
||||
switch (machine) {
|
||||
case 21:
|
||||
return "ppc64";
|
||||
case 22:
|
||||
return "s390";
|
||||
case 258:
|
||||
return "loongarch";
|
||||
default:
|
||||
return `elf-machine-${machine}`;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { goBinarySchema } from "../../src/domain/go/goBinary.js";
|
||||
import { rustBinarySchema } from "../../src/domain/rust/rustBinary.js";
|
||||
import { expect } from "vitest";
|
||||
import { toolContract } from "../../src/contracts/toolContracts.js";
|
||||
import { createGoBinaryFixture } from "../fixtures/go/image.js";
|
||||
import { createRustImage } from "../fixtures/rust/image.js";
|
||||
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
|
||||
import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
|
||||
import { join } from "node:path";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { cliTest } from "../support/cli/cliFixture.js";
|
||||
|
||||
cliTest(
|
||||
"preserves classifier-known Hexagon ELF identity through Go and Rust CLI/MCP",
|
||||
async ({ cli }) => {
|
||||
const root = await createTestTempDirectory("rea-elf-machine-identity-");
|
||||
const { client, call } = await connectLocalToolsMcp();
|
||||
for (const language of ["go", "rust"] as const) {
|
||||
const operation =
|
||||
language === "go" ? "inspect_go_binary" : "inspect_rust_binary";
|
||||
const command =
|
||||
language === "go" ? "inspect-go-binary" : "inspect-rust-binary";
|
||||
for (const item of [
|
||||
{ machine: 164, architecture: "hexagon", subject: "hexagon" },
|
||||
{ machine: 62, architecture: "amd64", subject: "x86_64" },
|
||||
]) {
|
||||
const bytes =
|
||||
language === "go"
|
||||
? createGoBinaryFixture({ omitBuildInfo: true }).bytes
|
||||
: createRustImage({
|
||||
format: "elf",
|
||||
omitSection: true,
|
||||
includeRustc: true,
|
||||
});
|
||||
bytes.writeUInt16LE(item.machine, 18);
|
||||
const path = join(root, `${language}-${item.machine}.elf`);
|
||||
await writeFile(path, bytes);
|
||||
|
||||
const cliResponse = await cli.run({
|
||||
arguments: [command, path, "--json"],
|
||||
});
|
||||
expect(
|
||||
cliResponse.exitCode,
|
||||
`${cliResponse.stderr}\n${JSON.stringify(cliResponse.json)}`,
|
||||
).toBe(0);
|
||||
const cliEvidence = toolContract(operation).outputSchema.parse(
|
||||
cliResponse.json,
|
||||
);
|
||||
const cliReport =
|
||||
language === "go"
|
||||
? goBinarySchema.parse(cliEvidence.normalized_result)
|
||||
: rustBinarySchema.parse(cliEvidence.normalized_result);
|
||||
expect(cliReport.architecture).toBe(item.architecture);
|
||||
expect(cliEvidence.subject?.architecture).toBe(item.subject);
|
||||
|
||||
const mcpResponse = await call(operation, { path });
|
||||
expect(mcpResponse.isError, JSON.stringify(mcpResponse)).not.toBe(true);
|
||||
const mcpEvidence = toolContract(operation).outputSchema.parse(
|
||||
mcpResponse.structuredContent,
|
||||
);
|
||||
const mcpReport =
|
||||
language === "go"
|
||||
? goBinarySchema.parse(mcpEvidence.normalized_result)
|
||||
: rustBinarySchema.parse(mcpEvidence.normalized_result);
|
||||
expect(mcpReport.architecture).toBe(item.architecture);
|
||||
expect(mcpEvidence.subject?.architecture).toBe(item.subject);
|
||||
}
|
||||
|
||||
const malformed =
|
||||
language === "go"
|
||||
? createGoBinaryFixture({ omitBuildInfo: true }).bytes
|
||||
: createRustImage({
|
||||
format: "elf",
|
||||
omitSection: true,
|
||||
includeRustc: true,
|
||||
});
|
||||
malformed[0] = 0;
|
||||
const path = join(root, `${language}-malformed.elf`);
|
||||
await writeFile(path, malformed);
|
||||
const cliFailure = await cli.run({
|
||||
arguments: [command, path, "--json"],
|
||||
});
|
||||
expect(cliFailure.exitCode).not.toBe(0);
|
||||
expect(cliFailure.json).not.toHaveProperty("normalized_result");
|
||||
const mcpFailure = await call(operation, { path });
|
||||
expect(mcpFailure.isError).toBe(true);
|
||||
expect(mcpFailure.structuredContent).toBeUndefined();
|
||||
}
|
||||
await client.ping();
|
||||
},
|
||||
30000,
|
||||
);
|
||||
@@ -17,6 +17,16 @@ import {
|
||||
GO_MODULE_TEXT,
|
||||
} from "../../fixtures/go/image.js";
|
||||
|
||||
it("uses the shared ELF classifier for Go image architecture", () => {
|
||||
const fixture = createGoBinaryFixture({ omitBuildInfo: true });
|
||||
fixture.bytes.writeUInt16LE(164, 18); // ELF EM_HEXAGON.
|
||||
expect(readGoBinaryImage(fixture.bytes)).toMatchObject({
|
||||
format: "elf",
|
||||
architecture: "hexagon",
|
||||
build_info: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves exact Mach-O protection masks for Go fallback selection", () => {
|
||||
const { bytes } = createGoBinaryFixture({
|
||||
format: "macho",
|
||||
|
||||
@@ -19,6 +19,7 @@ const packages = [
|
||||
source: "crates.io",
|
||||
kind: null,
|
||||
dependencies: [],
|
||||
features: [],
|
||||
root: false,
|
||||
},
|
||||
{
|
||||
@@ -27,6 +28,7 @@ const packages = [
|
||||
source: "local",
|
||||
kind: null,
|
||||
dependencies: [0],
|
||||
features: [],
|
||||
root: true,
|
||||
},
|
||||
];
|
||||
@@ -87,6 +89,20 @@ it("preserves the arm64_32 Mach-O CPU family when dependency metadata is absent"
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the shared ELF classifier for Rust image architecture", () => {
|
||||
const bytes = createRustImage({
|
||||
format: "elf",
|
||||
omitSection: true,
|
||||
includeRustc: true,
|
||||
});
|
||||
bytes.writeUInt16LE(164, 18); // ELF EM_HEXAGON.
|
||||
expect(readRustBinaryImage(bytes)).toMatchObject({
|
||||
format: "elf",
|
||||
architecture: "hexagon",
|
||||
auditable_metadata: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("ignores PE file-alignment padding after the dependency content", () => {
|
||||
const bytes = createRustImage({ format: "pe", includeRustc: false });
|
||||
const payloadBytes = rustDependencyPayload().length;
|
||||
|
||||
Reference in New Issue
Block a user