@@ -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+
4244typedef 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 & 0xFFFFFFFFFFFF ;
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
457550static 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