@@ -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,106 @@ 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+ static BOOLEAN NtfsReadMftRecord (PNTFS_VOLUME_INFO Volume , ULONGLONG MFTIndex , PNTFS_MFT_RECORD Buffer );
385+
386+ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelperList (
387+ PNTFS_VOLUME_INFO Volume ,
388+ PNTFS_ATTR_LIST_ATTR AttrListRecord ,
389+ PNTFS_ATTR_LIST_ATTR AttrListRecordEnd ,
390+ ULONG Type ,
391+ const WCHAR * Name ,
392+ ULONG NameLength ,
393+ ULONG Recursion )
394+ {
395+ ULONGLONG PrevMftIndex = -1 ;
396+ PNTFS_MFT_RECORD MftRecord = FrLdrTempAlloc (Volume -> MftRecordSize , TAG_NTFS_MFT );
397+ if (!MftRecord )
398+ return NULL ;
399+
400+ while (AttrListRecord < AttrListRecordEnd )
401+ {
402+ ULONGLONG MftIndex = AttrListRecord -> BaseFileRef & 0xFFFFFFFFFFFF ;
403+ ULONG AttrType = AttrListRecord -> Type ;
404+
405+ if (AttrType == NTFS_ATTR_TYPE_END )
406+ break ;
407+
408+ TRACE ("Recursion = %u, AttrListRecord->Type = 0x%x\n" , Recursion , AttrType );
409+
410+ if (AttrType == Type &&
411+ AttrListRecord -> NameLength == NameLength )
412+ {
413+ PWCHAR AttrListName ;
414+
415+ AttrListName = (PWCHAR )((PCHAR )AttrListRecord + AttrListRecord -> NameOffset );
416+ if (RtlEqualMemory (AttrListName , Name , NameLength << 1 ))
417+ {
418+ PNTFS_ATTR_CONTEXT Context ;
419+ PNTFS_ATTR_RECORD AttrRecord ;
420+ PNTFS_ATTR_RECORD AttrRecordEnd ;
421+
422+ if (PrevMftIndex != MftIndex )
423+ {
424+ PrevMftIndex = MftIndex ;
425+ if (!NtfsReadMftRecord (Volume , MftIndex , MftRecord ))
426+ goto skip ;
427+ }
428+
429+ AttrRecord = (PNTFS_ATTR_RECORD )((PCHAR )MftRecord + MftRecord -> AttributesOffset );
430+ AttrRecordEnd = (PNTFS_ATTR_RECORD )((PCHAR )MftRecord + Volume -> MftRecordSize );
431+
432+ Context = NtfsFindAttributeHelper (Volume , AttrRecord , AttrRecordEnd , Type , Name , NameLength , NTFS_MAX_ATTRIBUTE_LIST_RECURSION );
433+ if (Context )
434+ {
435+ FrLdrTempFree (MftRecord , TAG_NTFS_MFT );
436+ return Context ;
437+ }
438+ }
439+ }
440+
441+ skip :
442+ if (AttrListRecord -> RecLength == 0 )
443+ break ;
444+ AttrListRecord = (PNTFS_ATTR_LIST_ATTR )((PCHAR )AttrListRecord + AttrListRecord -> RecLength );
445+ }
446+
447+ FrLdrTempFree (MftRecord , TAG_NTFS_MFT );
448+ return NULL ;
449+ }
450+
451+ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper (
452+ PNTFS_VOLUME_INFO Volume ,
453+ PNTFS_ATTR_RECORD AttrRecord ,
454+ PNTFS_ATTR_RECORD AttrRecordEnd ,
455+ ULONG Type ,
456+ const WCHAR * Name ,
457+ ULONG NameLength ,
458+ ULONG Recursion )
375459{
376460 while (AttrRecord < AttrRecordEnd )
377461 {
378462 if (AttrRecord -> Type == NTFS_ATTR_TYPE_END )
379463 break ;
380464
381- if (AttrRecord -> Type == NTFS_ATTR_TYPE_ATTRIBUTE_LIST )
465+ TRACE ("Recursion = %u, AttrRecord->Type = 0x%x\n" , Recursion , AttrRecord -> Type );
466+
467+ /* Limit the $ATTRIBUTE_LIST recursion or else infinity loop */
468+ if (AttrRecord -> Type == NTFS_ATTR_TYPE_ATTRIBUTE_LIST && Recursion < NTFS_MAX_ATTRIBUTE_LIST_RECURSION )
382469 {
383470 PNTFS_ATTR_CONTEXT Context ;
384471 PNTFS_ATTR_CONTEXT ListContext ;
385472 PVOID ListBuffer ;
386473 ULONGLONG ListSize ;
387- PNTFS_ATTR_RECORD ListAttrRecord ;
388- PNTFS_ATTR_RECORD ListAttrRecordEnd ;
474+ PNTFS_ATTR_LIST_ATTR ListAttrRecord ;
475+ PNTFS_ATTR_LIST_ATTR ListAttrRecordEnd ;
389476
390477 ListContext = NtfsPrepareAttributeContext (AttrRecord );
391478
@@ -401,13 +488,13 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTF
401488 continue ;
402489 }
403490
404- ListAttrRecord = (PNTFS_ATTR_RECORD )ListBuffer ;
405- ListAttrRecordEnd = (PNTFS_ATTR_RECORD )((PCHAR )ListBuffer + ListSize );
491+ ListAttrRecord = (PNTFS_ATTR_LIST_ATTR )ListBuffer ;
492+ ListAttrRecordEnd = (PNTFS_ATTR_LIST_ATTR )((PCHAR )ListBuffer + ListSize );
406493
407494 if (NtfsReadAttribute (Volume , ListContext , 0 , ListBuffer , (ULONG )ListSize ) == ListSize )
408495 {
409- Context = NtfsFindAttributeHelper (Volume , ListAttrRecord , ListAttrRecordEnd ,
410- Type , Name , NameLength );
496+ Context = NtfsFindAttributeHelperList (Volume , ListAttrRecord , ListAttrRecordEnd ,
497+ Type , Name , NameLength , Recursion + 1 );
411498
412499 NtfsReleaseAttributeContext (ListContext );
413500 FrLdrTempFree (ListBuffer , TAG_NTFS_LIST );
@@ -417,23 +504,22 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttributeHelper(PNTFS_VOLUME_INFO Volume, PNTF
417504 }
418505 }
419506
420- if (AttrRecord -> Type == Type )
507+ if (AttrRecord -> Type == Type &&
508+ AttrRecord -> NameLength == NameLength &&
509+ NtfsGetAttributeSize (AttrRecord ) != 0 )
421510 {
422- if (AttrRecord -> NameLength == NameLength )
423- {
424- PWCHAR AttrName ;
511+ PWCHAR AttrName ;
425512
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- }
513+ AttrName = (PWCHAR )((PCHAR )AttrRecord + AttrRecord -> NameOffset );
514+ if (RtlEqualMemory (AttrName , Name , NameLength << 1 ))
515+ {
516+ /* Found it, fill up the context and return. */
517+ return NtfsPrepareAttributeContext (AttrRecord );
432518 }
433519 }
434520
435521 if (AttrRecord -> Length == 0 )
436- return NULL ;
522+ break ;
437523 AttrRecord = (PNTFS_ATTR_RECORD )((PCHAR )AttrRecord + AttrRecord -> Length );
438524 }
439525
@@ -451,7 +537,7 @@ static PNTFS_ATTR_CONTEXT NtfsFindAttribute(PNTFS_VOLUME_INFO Volume, PNTFS_MFT_
451537 for (NameLength = 0 ; Name [NameLength ] != 0 ; NameLength ++ )
452538 ;
453539
454- return NtfsFindAttributeHelper (Volume , AttrRecord , AttrRecordEnd , Type , Name , NameLength );
540+ return NtfsFindAttributeHelper (Volume , AttrRecord , AttrRecordEnd , Type , Name , NameLength , 0 );
455541}
456542
457543static BOOLEAN NtfsFixupRecord (PNTFS_VOLUME_INFO Volume , PNTFS_RECORD Record )
@@ -519,6 +605,7 @@ static BOOLEAN NtfsCompareFileName(PCHAR FileName, PNTFS_INDEX_ENTRY IndexEntry)
519605 EntryFileNameLength = IndexEntry -> FileName .FileNameLength ;
520606
521607#if DBG
608+ TRACE ("%s " , FileName );
522609 NtfsPrintFile (IndexEntry );
523610#endif
524611
0 commit comments