Files
reverse-engineering-anything/src/domain/elfFixedHeader.ts
T
morluto 34a4bb6508 fix(elf): centralize fixed header validation across consumers
Validate ELF identification/header versions and declared header bounds at the shared owner. Reuse parsed facts in target selection, Go, Dart and MIPS readers while preserving their stricter format policies and x32 support.

Repair synthetic ELF fixtures and remove a superseded Go error-text assertion. Validation: 74 source tests, 202 filesystem/Go/MIPS boundary tests, typecheck and lint. No new real-provider claims.
2026-10-13 08:07:58 +08:00

56 lines
2.0 KiB
TypeScript

import { err, ok, type Result } from "./result.js";
export interface ElfFixedHeader {
readonly elfClass: 32 | 64;
readonly byteOrder: "little" | "big";
readonly headerSize: number;
}
/**
* Validate the common, fixed ELF header commitments.
*
* `bytes` may be a bounded prefix. `totalBytes` is the containing file size,
* so the declared header extent is checked against the file without requiring
* the whole declared extent to be present in this prefix.
*/
export const readElfFixedHeader = (
bytes: Buffer,
totalBytes = bytes.length,
): Result<ElfFixedHeader, string> => {
if (bytes.length >= 4 && bytes.toString("hex", 0, 4) !== "7f454c46")
return err("not an ELF image");
if (bytes.length < 16) return err("ELF identification is truncated");
const classByte = bytes[4];
if (classByte !== 1 && classByte !== 2) return err("unsupported ELF class");
const dataByte = bytes[5];
if (dataByte !== 1 && dataByte !== 2)
return err("unsupported ELF endianness");
if (bytes[6] !== 1) return err("unsupported ELF identification version");
const elfClass = classByte === 1 ? 32 : 64;
const minimumSize = elfClass === 32 ? 52 : 64;
if (
!Number.isSafeInteger(totalBytes) ||
totalBytes < bytes.length ||
totalBytes < minimumSize ||
bytes.length < minimumSize
)
return err(
`truncated ELF header: an ELF${elfClass} header needs ${minimumSize} bytes; the file has ${totalBytes}`,
);
const littleEndian = dataByte === 1;
const readU16 = (offset: number): number =>
littleEndian ? bytes.readUInt16LE(offset) : bytes.readUInt16BE(offset);
const readU32 = (offset: number): number =>
littleEndian ? bytes.readUInt32LE(offset) : bytes.readUInt32BE(offset);
if (readU32(20) !== 1) return err("unsupported ELF header version");
const headerSize = readU16(elfClass === 32 ? 40 : 52);
if (headerSize < minimumSize || headerSize > totalBytes)
return err("invalid ELF header size");
return ok({
elfClass,
byteOrder: littleEndian ? "little" : "big",
headerSize,
});
};