mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 01:41:21 +00:00
fix(ntfs): validate first attribute bounds in FILE records
Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
1 parent
7712e3185e
commit
8d45cb45c4
3 files changed
+29
-9
No files matched your search
@@ -106,7 +106,7 @@ it("reports incomplete coverage when FILE extents contradict the record slots",
|
||||
);
|
||||
expect(inventory.coverage.status).toBe("unknown");
|
||||
expect(inventory.limitations).toContainEqual(
|
||||
"2 FILE record(s) declare inconsistent used or total byte counts, beginning at offset 0",
|
||||
"2 FILE record(s) declare inconsistent record extents, beginning at offset 0",
|
||||
);
|
||||
expect(inventory.occurrences[0]?.format_metadata).toMatchObject({
|
||||
record_count: 2,
|
||||
|
||||
@@ -56,9 +56,11 @@ const recordOf = (options: RecordOptions = {}): Uint8Array => {
|
||||
|
||||
view.setUint16(16, sequenceNumber, true);
|
||||
view.setUint16(18, options.hardLinkCount ?? 1, true);
|
||||
view.setUint16(20, 56, true);
|
||||
const firstAttributeOffset =
|
||||
Math.ceil((48 + Math.max(0, usaEntries) * 2) / 8) * 8;
|
||||
view.setUint16(20, firstAttributeOffset, true);
|
||||
view.setUint16(22, options.flags ?? 0x0001, true);
|
||||
view.setUint32(24, 56, true);
|
||||
view.setUint32(24, firstAttributeOffset, true);
|
||||
view.setUint32(28, recordBytes, true);
|
||||
view.setBigUint64(32, options.baseRecordReference ?? 0n, true);
|
||||
view.setUint16(40, 0, true);
|
||||
@@ -121,6 +123,18 @@ describe("MFT header facts", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each([0, 49, 64])(
|
||||
"reports an invalid first attribute offset %i",
|
||||
(offset) => {
|
||||
const record = recordOf();
|
||||
new DataView(record.buffer).setUint16(20, offset, true);
|
||||
const parsed = parseMftImage(record);
|
||||
if (!parsed.ok) throw new Error(parsed.error.message);
|
||||
expect(parsed.value.records[0]?.extentValid).toBe(false);
|
||||
expect(parsed.value.limitations.join(" ")).toContain("inconsistent");
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps the inline header window separate from the parsed record count", () => {
|
||||
const parsed = parseMftImage(
|
||||
streamOf(...Array.from({ length: 33 }, () => recordOf())),
|
||||
|
||||
@@ -301,7 +301,7 @@ const scanMft = (
|
||||
|
||||
if (firstInvalidExtentOffset !== undefined)
|
||||
limitations.push(
|
||||
`${String(invalidExtents)} FILE record(s) declare inconsistent used or total byte counts, beginning at offset ${String(firstInvalidExtentOffset)}`,
|
||||
`${String(invalidExtents)} FILE record(s) declare inconsistent record extents, beginning at offset ${String(firstInvalidExtentOffset)}`,
|
||||
);
|
||||
|
||||
const truncatedTailBytes = bytes.length % recordBytes;
|
||||
@@ -359,6 +359,10 @@ const readRecord = (
|
||||
const fixups = verifyFixups(record, view, usaOffset);
|
||||
const usedBytes = view.getUint32(RECORD_HEADER.usedBytes, true);
|
||||
const totalBytes = view.getUint32(RECORD_HEADER.totalBytes, true);
|
||||
const firstAttributeOffset = view.getUint16(
|
||||
RECORD_HEADER.firstAttributeOffset,
|
||||
true,
|
||||
);
|
||||
|
||||
return {
|
||||
index,
|
||||
@@ -374,7 +378,12 @@ const readRecord = (
|
||||
totalBytes === recordBytes &&
|
||||
usedBytes >= NTFS_MFT_MIN_RECORD_BYTES &&
|
||||
usedBytes % 8 === 0 &&
|
||||
usedBytes <= totalBytes,
|
||||
usedBytes <= totalBytes &&
|
||||
firstAttributeOffset % 8 === 0 &&
|
||||
firstAttributeOffset >= NTFS_MFT_MIN_RECORD_BYTES &&
|
||||
firstAttributeOffset <= usedBytes &&
|
||||
(fixups.malformed ||
|
||||
firstAttributeOffset >= usaOffset + fixups.entries * 2),
|
||||
baseRecordReference:
|
||||
baseRecordReference === 0n
|
||||
? null
|
||||
@@ -386,10 +395,7 @@ const readRecord = (
|
||||
logFileSequenceNumber: view
|
||||
.getBigUint64(RECORD_HEADER.logFileSequenceNumber, true)
|
||||
.toString(),
|
||||
firstAttributeOffset: view.getUint16(
|
||||
RECORD_HEADER.firstAttributeOffset,
|
||||
true,
|
||||
),
|
||||
firstAttributeOffset,
|
||||
nextAttributeId: view.getUint16(RECORD_HEADER.nextAttributeId, true),
|
||||
fixups,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user