[NTFS] Correctly find attributes stored in another file record in MFT (and referenced in data stream)

This commit is contained in:
Sylvain Deverre 2019-08-08 22:09:13 +02:00 committed by Colin Finck
parent 86b8aeb3f2
commit 4d3df0da50
3 changed files with 147 additions and 27 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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,