From 4d3df0da50b99f8f868449d262b88ffe2ac1d789 Mon Sep 17 00:00:00 2001 From: Sylvain Deverre Date: Thu, 8 Aug 2019 22:09:13 +0200 Subject: [PATCH] [NTFS] Correctly find attributes stored in another file record in MFT (and referenced in data stream) --- drivers/filesystems/ntfs/attrib.c | 93 ++++++++++++++++++++++--------- drivers/filesystems/ntfs/mft.c | 56 +++++++++++++++++++ drivers/filesystems/ntfs/ntfs.h | 25 ++++++++- 3 files changed, 147 insertions(+), 27 deletions(-) diff --git a/drivers/filesystems/ntfs/attrib.c b/drivers/filesystems/ntfs/attrib.c index 1a04b763a2a..006465ce975 100644 --- a/drivers/filesystems/ntfs/attrib.c +++ b/drivers/filesystems/ntfs/attrib.c @@ -1258,7 +1258,74 @@ InternalReadNonResidentAttributes(PFIND_ATTR_CONTXT Context) } ReleaseAttributeContext(ListContext); - Context->NonResidentEnd = (PNTFS_ATTR_RECORD)((PCHAR)Context->NonResidentStart + ListSize); + Context->NonResidentEnd = (PNTFS_ATTRIBUTE_LIST_ITEM)((PCHAR)Context->NonResidentStart + ListSize); + return STATUS_SUCCESS; +} + +static +PNTFS_ATTRIBUTE_LIST_ITEM +InternalGetNextAttributeListItem(PFIND_ATTR_CONTXT Context) +{ + PNTFS_ATTRIBUTE_LIST_ITEM NextItem; + + if (Context->NonResidentCur == (PVOID)-1) + { + return NULL; + } + + if (Context->NonResidentCur == NULL || Context->NonResidentCur->Type == AttributeEnd) + { + Context->NonResidentCur = (PVOID)-1; + return NULL; + } + + if (Context->NonResidentCur->Length == 0) + { + DPRINT1("Broken length list entry length !"); + Context->NonResidentCur = (PVOID)-1; + return NULL; + } + + NextItem = (PNTFS_ATTRIBUTE_LIST_ITEM)((PCHAR)Context->NonResidentCur + Context->NonResidentCur->Length); + if (NextItem->Length == 0 || NextItem->Type == AttributeEnd) + { + Context->NonResidentCur = (PVOID)-1; + return NULL; + } + + if (NextItem < Context->NonResidentStart || NextItem > Context->NonResidentEnd) + { + Context->NonResidentCur = (PVOID)-1; + return NULL; + } + + Context->NonResidentCur = NextItem; + return NextItem; +} + +NTSTATUS +FindFirstAttributeListItem(PFIND_ATTR_CONTXT Context, + PNTFS_ATTRIBUTE_LIST_ITEM *Item) +{ + if (Context->NonResidentStart == NULL || Context->NonResidentStart->Type == AttributeEnd) + { + return STATUS_UNSUCCESSFUL; + } + + Context->NonResidentCur = Context->NonResidentStart; + *Item = Context->NonResidentCur; + return STATUS_SUCCESS; +} + +NTSTATUS +FindNextAttributeListItem(PFIND_ATTR_CONTXT Context, + PNTFS_ATTRIBUTE_LIST_ITEM *Item) +{ + *Item = InternalGetNextAttributeListItem(Context); + if (*Item == NULL) + { + return STATUS_UNSUCCESSFUL; + } return STATUS_SUCCESS; } @@ -1308,30 +1375,6 @@ InternalGetNextAttribute(PFIND_ATTR_CONTXT Context) return NULL; } - if (Context->CurrAttr < Context->NonResidentStart || - Context->CurrAttr >= Context->NonResidentEnd) - { - Context->CurrAttr = Context->NonResidentStart; - } - else if (Context->CurrAttr->Length != 0) - { - NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Context->CurrAttr + Context->CurrAttr->Length); - Context->Offset += ((ULONG_PTR)NextAttribute - (ULONG_PTR)Context->CurrAttr); - Context->CurrAttr = NextAttribute; - } - else - { - DPRINT1("Broken length!\n"); - Context->CurrAttr = (PVOID)-1; - return NULL; - } - - if (Context->CurrAttr < Context->NonResidentEnd && - Context->CurrAttr->Type != AttributeEnd) - { - return Context->CurrAttr; - } - Context->CurrAttr = (PVOID)-1; return NULL; } diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c index f03074cdfda..e1411f0ac96 100644 --- a/drivers/filesystems/ntfs/mft.c +++ b/drivers/filesystems/ntfs/mft.c @@ -140,6 +140,7 @@ FindAttribute(PDEVICE_EXTENSION Vcb, NTSTATUS Status; FIND_ATTR_CONTXT Context; PNTFS_ATTR_RECORD Attribute; + PNTFS_ATTRIBUTE_LIST_ITEM AttrListItem; DPRINT("FindAttribute(%p, %p, 0x%x, %S, %lu, %p, %p)\n", Vcb, MftRecord, Type, Name, NameLength, AttrCtx, Offset); @@ -184,6 +185,61 @@ FindAttribute(PDEVICE_EXTENSION Vcb, Status = FindNextAttribute(&Context, &Attribute); } + /* No attribute found, check if it is referenced in another file record */ + Status = FindFirstAttributeListItem(&Context, &AttrListItem); + while (NT_SUCCESS(Status)) + { + if (AttrListItem->Type == Type && AttrListItem->NameLength == NameLength) + { + if (NameLength != 0) + { + PWCHAR AttrName; + + AttrName = (PWCHAR)((PCHAR)AttrListItem + AttrListItem->NameOffset); + DPRINT("%.*S, %.*S\n", AttrListItem->NameLength, AttrName, NameLength, Name); + if (RtlCompareMemory(AttrName, Name, NameLength * sizeof(WCHAR)) == (NameLength * sizeof(WCHAR))) + { + Found = TRUE; + } + } + else + { + Found = TRUE; + } + + if (Found == TRUE) + { + /* Get the MFT Index of attribute */ + ULONGLONG MftIndex; + PFILE_RECORD_HEADER RemoteHdr; + + MftIndex = AttrListItem->MFTIndex & NTFS_MFT_MASK; + RemoteHdr = ExAllocateFromNPagedLookasideList(&Vcb->FileRecLookasideList); + + if (RemoteHdr == NULL) + { + FindCloseAttribute(&Context); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Check we are not reading ourselves */ + if (MftRecord->MFTRecordNumber == MftIndex) + { + DPRINT1("Attribute list references missing attribute to this file entry !"); + ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr); + FindCloseAttribute(&Context); + return STATUS_OBJECT_NAME_NOT_FOUND; + } + /* Read the new file record */ + ReadFileRecord(Vcb, MftIndex, RemoteHdr); + Status = FindAttribute(Vcb, RemoteHdr, Type, Name, NameLength, AttrCtx, Offset); + ExFreeToNPagedLookasideList(&Vcb->FileRecLookasideList, RemoteHdr); + FindCloseAttribute(&Context); + return Status; + } + } + Status = FindNextAttributeListItem(&Context, &AttrListItem); + } FindCloseAttribute(&Context); return STATUS_OBJECT_NAME_NOT_FOUND; } diff --git a/drivers/filesystems/ntfs/ntfs.h b/drivers/filesystems/ntfs/ntfs.h index c50a077e1c1..aa85b810883 100644 --- a/drivers/filesystems/ntfs/ntfs.h +++ b/drivers/filesystems/ntfs/ntfs.h @@ -300,6 +300,17 @@ typedef struct }; } NTFS_ATTR_RECORD, *PNTFS_ATTR_RECORD; +typedef struct +{ + ULONG Type; + USHORT Length; + UCHAR NameLength; + UCHAR NameOffset; + ULONGLONG StartingVCN; + ULONGLONG MFTIndex; + USHORT Instance; +} NTFS_ATTRIBUTE_LIST_ITEM, *PNTFS_ATTRIBUTE_LIST_ITEM; + // The beginning and length of an attribute record are always aligned to an 8-byte boundary, // relative to the beginning of the file record. #define ATTR_RECORD_ALIGNMENT 8 @@ -486,6 +497,7 @@ typedef struct _NTFS_ATTR_CONTEXT ULONGLONG CacheRunCurrentOffset; LARGE_MCB DataRunsMCB; ULONGLONG FileMFTIndex; + ULONGLONG FileOwnerMFTIndex; /* If attribute list attribute, reference the original file */ PNTFS_ATTR_RECORD pRecord; } NTFS_ATTR_CONTEXT, *PNTFS_ATTR_CONTEXT; @@ -534,8 +546,9 @@ typedef struct _FIND_ATTR_CONTXT PNTFS_ATTR_RECORD FirstAttr; PNTFS_ATTR_RECORD CurrAttr; PNTFS_ATTR_RECORD LastAttr; - PNTFS_ATTR_RECORD NonResidentStart; - PNTFS_ATTR_RECORD NonResidentEnd; + PNTFS_ATTRIBUTE_LIST_ITEM NonResidentStart; + PNTFS_ATTRIBUTE_LIST_ITEM NonResidentEnd; + PNTFS_ATTRIBUTE_LIST_ITEM NonResidentCur; ULONG Offset; } FIND_ATTR_CONTXT, *PFIND_ATTR_CONTXT; @@ -659,6 +672,14 @@ PFILENAME_ATTRIBUTE GetBestFileNameFromRecord(PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER FileRecord); +NTSTATUS +FindFirstAttributeListItem(PFIND_ATTR_CONTXT Context, + PNTFS_ATTRIBUTE_LIST_ITEM *Item); + +NTSTATUS +FindNextAttributeListItem(PFIND_ATTR_CONTXT Context, + PNTFS_ATTRIBUTE_LIST_ITEM *Item); + NTSTATUS FindFirstAttribute(PFIND_ATTR_CONTXT Context, PDEVICE_EXTENSION Vcb, -- 2.17.1