Skip to content

Commit 7c99314

Browse files
committed
[FREELDR] Fix AttributeList parsing on NTFS driver
1 parent 6dd0406 commit 7c99314

File tree

1 file changed

+116
-22
lines changed
  • boot/freeldr/freeldr/lib/fs

1 file changed

+116
-22
lines changed

boot/freeldr/freeldr/lib/fs/ntfs.c

Lines changed: 116 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ DBG_DEFAULT_CHANNEL(FILESYSTEM);
3939
#define TAG_NTFS_VOLUME 'VftN'
4040
#define TAG_NTFS_DATA 'DftN'
4141

42+
#define NTFS_MAX_ATTRIBUTE_LIST_RECURSION 8
43+
4244
typedef struct _NTFS_VOLUME_INFO
4345
{
4446
NTFS_BOOTSECTOR BootSector;
@@ -371,21 +373,111 @@ static ULONG NtfsReadAttribute(PNTFS_VOLUME_INFO Volume, PNTFS_ATTR_CONTEXT Cont
371373
return AlreadyRead;
372374
}
373375

374-
static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTFS_ATTR_RECORD AttrRecord, PNTFS_ATTR_RECORD AttrRecordEnd, ULONG Type, const WCHAR *Name, ULONG NameLength)
376+
static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(
377+
PNTFS_VOLUME_INFO Volume,
378+
PNTFS_ATTR_RECORD AttrRecord,
379+
PNTFS_ATTR_RECORD AttrRecordEnd,
380+
ULONG Type,
381+
const WCHAR *Name,
382+
ULONG NameLength,
383+
ULONG Recursion,
384+
ULONG Instance);
385+
static BOOLEAN NtfsReadMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, PNTFS_MFT_RECORD Buffer);
386+
387+
static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelperList(
388+
PNTFS_VOLUME_INFO Volume,
389+
PNTFS_ATTR_LIST_ATTR AttrListRecord,
390+
PNTFS_ATTR_LIST_ATTR AttrListRecordEnd,
391+
ULONG Type,
392+
const WCHAR *Name,
393+
ULONG NameLength,
394+
ULONG Recursion)
395+
{
396+
ULONGLONG PrevMftIndex = -1;
397+
PNTFS_MFT_RECORD MftRecord = FrLdrTempAlloc(Volume->MftRecordSize, TAG_NTFS_MFT);
398+
if (!MftRecord)
399+
return NULL;
400+
401+
while (AttrListRecord < AttrListRecordEnd)
402+
{
403+
ULONGLONG MftIndex = AttrListRecord->BaseFileRef & NTFS_MFT_MASK;
404+
ULONG AttrType = AttrListRecord->Type;
405+
ULONG AttrId = AttrListRecord->AttrId;
406+
407+
if (AttrType == NTFS_ATTR_TYPE_END)
408+
break;
409+
410+
TRACE("Recursion = %u, AttrListRecord->Type = 0x%x\n", Recursion, AttrType);
411+
412+
if (AttrType == Type &&
413+
AttrListRecord->NameLength == NameLength)
414+
{
415+
PWCHAR AttrListName;
416+
417+
AttrListName = (PWCHAR)((PCHAR)AttrListRecord + AttrListRecord->NameOffset);
418+
if (RtlEqualMemory(AttrListName, Name, NameLength << 1))
419+
{
420+
PNTFS_ATTR_CONTEXT Context;
421+
PNTFS_ATTR_RECORD AttrRecord;
422+
PNTFS_ATTR_RECORD AttrRecordEnd;
423+
424+
if (PrevMftIndex != MftIndex)
425+
{
426+
PrevMftIndex = MftIndex;
427+
if (!NtfsReadMftRecord(Volume, MftIndex, MftRecord))
428+
goto skip;
429+
}
430+
431+
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + MftRecord->AttributesOffset);
432+
AttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)MftRecord + Volume->MftRecordSize);
433+
434+
Context = NtfsFindAttributeHelper(Volume, AttrRecord, AttrRecordEnd,
435+
Type, Name, NameLength,
436+
NTFS_MAX_ATTRIBUTE_LIST_RECURSION, AttrId);
437+
if (Context)
438+
{
439+
FrLdrTempFree(MftRecord, TAG_NTFS_MFT);
440+
return Context;
441+
}
442+
}
443+
}
444+
445+
skip:
446+
if (AttrListRecord->RecLength == 0)
447+
break;
448+
AttrListRecord = (PNTFS_ATTR_LIST_ATTR)((PCHAR)AttrListRecord + AttrListRecord->RecLength);
449+
}
450+
451+
FrLdrTempFree(MftRecord, TAG_NTFS_MFT);
452+
return NULL;
453+
}
454+
455+
static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(
456+
PNTFS_VOLUME_INFO Volume,
457+
PNTFS_ATTR_RECORD AttrRecord,
458+
PNTFS_ATTR_RECORD AttrRecordEnd,
459+
ULONG Type,
460+
const WCHAR *Name,
461+
ULONG NameLength,
462+
ULONG Recursion,
463+
ULONG Instance)
375464
{
376465
while (AttrRecord < AttrRecordEnd)
377466
{
378467
if (AttrRecord->Type == NTFS_ATTR_TYPE_END)
379468
break;
380469

381-
if (AttrRecord->Type == NTFS_ATTR_TYPE_ATTRIBUTE_LIST)
470+
TRACE("Recursion = %u, AttrRecord->Type = 0x%x\n", Recursion, AttrRecord->Type);
471+
472+
/* Limit the $ATTRIBUTE_LIST recursion or else infinity loop */
473+
if (AttrRecord->Type == NTFS_ATTR_TYPE_ATTRIBUTE_LIST && Recursion < NTFS_MAX_ATTRIBUTE_LIST_RECURSION)
382474
{
383475
PNTFS_ATTR_CONTEXT Context;
384476
PNTFS_ATTR_CONTEXT ListContext;
385477
PVOID ListBuffer;
386478
ULONGLONG ListSize;
387-
PNTFS_ATTR_RECORD ListAttrRecord;
388-
PNTFS_ATTR_RECORD ListAttrRecordEnd;
479+
PNTFS_ATTR_LIST_ATTR ListAttrRecord;
480+
PNTFS_ATTR_LIST_ATTR ListAttrRecordEnd;
389481

390482
ListContext = NtfsPrepareAttributeContext(AttrRecord);
391483

@@ -401,13 +493,14 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTF
401493
continue;
402494
}
403495

404-
ListAttrRecord = (PNTFS_ATTR_RECORD)ListBuffer;
405-
ListAttrRecordEnd = (PNTFS_ATTR_RECORD)((PCHAR)ListBuffer + ListSize);
496+
ListAttrRecord = (PNTFS_ATTR_LIST_ATTR)ListBuffer;
497+
ListAttrRecordEnd = (PNTFS_ATTR_LIST_ATTR)((PCHAR)ListBuffer + ListSize);
406498

407499
if (NtfsReadAttribute(Volume, ListContext, 0, ListBuffer, (ULONG)ListSize) == ListSize)
408500
{
409-
Context = NtfsFindAttributeHelper(Volume, ListAttrRecord, ListAttrRecordEnd,
410-
Type, Name, NameLength);
501+
Context = NtfsFindAttributeHelperList(Volume, ListAttrRecord, ListAttrRecordEnd,
502+
Type, Name, NameLength,
503+
Recursion + 1);
411504

412505
NtfsReleaseAttributeContext(ListContext);
413506
FrLdrTempFree(ListBuffer, TAG_NTFS_LIST);
@@ -417,23 +510,23 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTF
417510
}
418511
}
419512

420-
if (AttrRecord->Type == Type)
513+
if (AttrRecord->Type == Type &&
514+
AttrRecord->NameLength == NameLength &&
515+
NtfsGetAttributeSize(AttrRecord) != 0 &&
516+
(Instance == (ULONG)-1 || (ULONG)AttrRecord->Instance == Instance))
421517
{
422-
if (AttrRecord->NameLength == NameLength)
423-
{
424-
PWCHAR AttrName;
518+
PWCHAR AttrName;
425519

426-
AttrName = (PWCHAR)((PCHAR)AttrRecord + AttrRecord->NameOffset);
427-
if (RtlEqualMemory(AttrName, Name, NameLength << 1))
428-
{
429-
/* Found it, fill up the context and return. */
430-
return NtfsPrepareAttributeContext(AttrRecord);
431-
}
520+
AttrName = (PWCHAR)((PCHAR)AttrRecord + AttrRecord->NameOffset);
521+
if (RtlEqualMemory(AttrName, Name, NameLength << 1))
522+
{
523+
/* Found it, fill up the context and return. */
524+
return NtfsPrepareAttributeContext(AttrRecord);
432525
}
433526
}
434527

435528
if (AttrRecord->Length == 0)
436-
return NULL;
529+
break;
437530
AttrRecord = (PNTFS_ATTR_RECORD)((PCHAR)AttrRecord + AttrRecord->Length);
438531
}
439532

@@ -451,7 +544,7 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttribute(PNTFS_VOLUME_INFO Volume, PNTFS_MFT_
451544
for (NameLength = 0; Name[NameLength] != 0; NameLength++)
452545
;
453546

454-
return NtfsFindAttributeHelper(Volume, AttrRecord, AttrRecordEnd, Type, Name, NameLength);
547+
return NtfsFindAttributeHelper(Volume, AttrRecord, AttrRecordEnd, Type, Name, NameLength, 0, -1);
455548
}
456549

457550
static BOOLEAN NtfsFixupRecord(PNTFS_VOLUME_INFO Volume, PNTFS_RECORD Record)
@@ -519,6 +612,7 @@ static BOOLEAN NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry)
519612
EntryFileNameLength = IndexEntry->FileName.FileNameLength;
520613

521614
#if DBG
615+
TRACE("%s ", FileName);
522616
NtfsPrintFile(IndexEntry);
523617
#endif
524618

@@ -599,7 +693,7 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
599693
FrLdrTempFree(MftRecord, TAG_NTFS_MFT);
600694
return TRUE;
601695
}
602-
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
696+
IndexEntry = (PNTFS_INDEX_ENTRY)((PCHAR)IndexEntry + IndexEntry->Length);
603697
}
604698

605699
if (IndexRoot->IndexHeader.Flags & NTFS_LARGE_INDEX)
@@ -670,7 +764,7 @@ static BOOLEAN NtfsFindMftRecord(PNTFS_VOLUME_INFO Volume, ULONGLONG MFTIndex, P
670764

671765
/* FIXME */
672766
IndexEntry = (PNTFS_INDEX_ENTRY)(IndexRecord + 0x18 + *(USHORT *)(IndexRecord + 0x18));
673-
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexBlockSize);
767+
IndexEntryEnd = (PNTFS_INDEX_ENTRY)(IndexRecord + IndexBlockSize);
674768

675769
while (IndexEntry < IndexEntryEnd &&
676770
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))

0 commit comments

Comments
 (0)