mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
8.3 KiB
282 lines
8.3 KiB
/*++
|
|
|
|
Copyright (c) 1989-1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
check.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the property set check support
|
|
|
|
|
|
--*/
|
|
|
|
#include <viewprop.h> // needs propset.h and ntfsprop.h
|
|
|
|
#define Dbg DEBUG_TRACE_PROP_FSCTL
|
|
|
|
|
|
VOID
|
|
CheckPropertySet (
|
|
IN PPROPERTY_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs validates the syntax of the property set
|
|
stream.
|
|
|
|
Arguments:
|
|
|
|
Context - context of call
|
|
|
|
Return Value:
|
|
|
|
Nothing. May raise if object is corrupt.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPROPERTY_SET_HEADER Header = Context->Header;
|
|
PPROPERTY_ID_TABLE IdTable = Context->IdTable;
|
|
PPROPERTY_HEAP_HEADER HeapHeader = Context->HeapHeader;
|
|
PPROPERTY_HEAP_ENTRY HeapEntry;
|
|
ULONG Length = (ULONG) Context->Attribute->Header.FileSize.QuadPart ;
|
|
ULONG i;
|
|
|
|
if (
|
|
//
|
|
// Verify initial length
|
|
//
|
|
|
|
(Length < sizeof( PROPERTY_SET_HEADER )
|
|
DebugDoit( && PROPASSERT( !"Not enough room for header" ))) ||
|
|
|
|
//
|
|
// Verify header of attribute. Check the signature and format stamp.
|
|
//
|
|
|
|
(Header->wByteOrder != 0xFFFE
|
|
DebugDoit( && PROPASSERT( !"Byte order invalid" ))) ||
|
|
(Header->wFormat != PSH_FORMAT_VERSION
|
|
DebugDoit( && PROPASSERT( !"Format version invalid" ))) ||
|
|
((HIWORD( Header->dwOSVer ) > 2 ||
|
|
LOBYTE( LOWORD( Header->dwOSVer )) > 5)
|
|
DebugDoit( && PROPASSERT( !"dwOSVer invalid" ))) ||
|
|
|
|
//
|
|
// Verify offsets of table and heap are valid.
|
|
//
|
|
|
|
(Header->IdTableOffset >= Length
|
|
DebugDoit( && PROPASSERT( !"IdTable offset invalid" ))) ||
|
|
(Header->IdTableOffset != LongAlign( Header->IdTableOffset )
|
|
DebugDoit( && PROPASSERT( !"IdTable misaligned" ))) ||
|
|
(Header->ValueHeapOffset >= Length
|
|
DebugDoit( && PROPASSERT( !"ValueHeap offset invalid" ))) ||
|
|
(Header->ValueHeapOffset != LongAlign( Header->ValueHeapOffset )
|
|
DebugDoit( && PROPASSERT( !"ValueHeap misaligned" ))) ||
|
|
|
|
//
|
|
// Verify that the table fits below the value heap
|
|
//
|
|
|
|
(PROPERTY_ID_TABLE_SIZE( IdTable->MaximumPropertyCount ) >
|
|
Header->ValueHeapOffset - Header->IdTableOffset
|
|
DebugDoit( && PROPASSERT( !"IdTable overlaps ValueHeap" ))) ||
|
|
|
|
//
|
|
// Verify that the heap is within the stream
|
|
//
|
|
|
|
(Header->ValueHeapOffset + HeapHeader->PropertyHeapLength > Length
|
|
DebugDoit( && PROPASSERT( !"ValueHeap beyond end of stream" ))) ||
|
|
|
|
//
|
|
// Verify table counts are correct
|
|
//
|
|
|
|
(IdTable->PropertyCount > IdTable->MaximumPropertyCount
|
|
DebugDoit( && PROPASSERT( !"IdTable counts are incorrect" )))
|
|
|
|
) {
|
|
|
|
NtfsRaiseStatus( Context->IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Context->Object );
|
|
}
|
|
|
|
for (i = 0; i < IdTable->PropertyCount; i++) {
|
|
PPROPERTY_TABLE_ENTRY Entry = (PPROPERTY_TABLE_ENTRY) &IdTable->Entry[i];
|
|
if (
|
|
//
|
|
// Verify sorting
|
|
//
|
|
|
|
(i > 1 && Entry[-1].PropertyId >= Entry[0].PropertyId
|
|
DebugDoit( && PROPASSERT( !"IdTable entry sort invalid" ))) ||
|
|
(i < IdTable->PropertyCount - 1 && Entry[0].PropertyId >= Entry[1].PropertyId
|
|
DebugDoit( && PROPASSERT( !"IdTable entry sort invalid 2" ))) ||
|
|
|
|
//
|
|
// Verify offset points within heap
|
|
//
|
|
|
|
(Entry[0].PropertyValueOffset >= HeapHeader->PropertyHeapLength
|
|
DebugDoit( && PROPASSERT( !"IdTable entry offset invalid" ))) ||
|
|
|
|
//
|
|
// Verify the back pointer matches
|
|
//
|
|
|
|
(Entry[0].PropertyId != GET_HEAP_ENTRY( HeapHeader, Entry[0].PropertyValueOffset )->PropertyId
|
|
DebugDoit( && PROPASSERT( !"Backpointer invalid" )))
|
|
) {
|
|
|
|
NtfsRaiseStatus( Context->IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Context->Object );
|
|
}
|
|
}
|
|
|
|
HeapEntry = FIRST_HEAP_ENTRY( HeapHeader );
|
|
while (!IS_LAST_HEAP_ENTRY( HeapHeader, HeapEntry )) {
|
|
|
|
if (HeapEntry->PropertyId != PID_ILLEGAL) {
|
|
ULONG Index =
|
|
BinarySearchIdTable( Context, HeapEntry->PropertyId );
|
|
|
|
if (
|
|
//
|
|
// Verify length is aligned
|
|
//
|
|
|
|
(HeapEntry->PropertyValueLength != LongAlign( HeapEntry->PropertyValueLength )
|
|
DebugDoit( && PROPASSERT( !"Property length misaligned" ))) ||
|
|
//
|
|
// Verify backpointer works
|
|
//
|
|
|
|
(Index >= IdTable->PropertyCount
|
|
DebugDoit( && PROPASSERT( !"Backpointer after end of table" ))) ||
|
|
|
|
//
|
|
// Backpointer Id agrees
|
|
//
|
|
|
|
(IdTable->Entry[Index].PropertyId != HeapEntry->PropertyId
|
|
DebugDoit( && PROPASSERT( !"Backpointer not found in table" ))) ||
|
|
|
|
//
|
|
// Backpointer offset agrees
|
|
//
|
|
|
|
(IdTable->Entry[Index].PropertyValueOffset != HeapOffset( Context, HeapEntry)
|
|
DebugDoit( && PROPASSERT( !"Backpointer not found in table" ))) ||
|
|
|
|
//
|
|
// Name length is word aligned
|
|
//
|
|
|
|
(HeapEntry->PropertyNameLength != WordAlign( HeapEntry->PropertyNameLength )
|
|
DebugDoit( && PROPASSERT( !"Name is odd number of bytes" ))) ||
|
|
|
|
//
|
|
// Verify property is entirely in heap
|
|
//
|
|
|
|
(HeapOffset( Context, NEXT_HEAP_ENTRY( HeapEntry)) > HeapHeader->PropertyHeapLength
|
|
DebugDoit( && PROPASSERT( !"Property Value overlaps end of heap" )))
|
|
|
|
) {
|
|
|
|
NtfsRaiseStatus( Context->IrpContext, STATUS_FILE_CORRUPT_ERROR, NULL, Context->Object );
|
|
}
|
|
}
|
|
|
|
HeapEntry = NEXT_HEAP_ENTRY( HeapEntry );
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpPropertyData (
|
|
IN PPROPERTY_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs validates the syntax of the property set
|
|
stream.
|
|
|
|
Arguments:
|
|
|
|
Context - context of call
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PPROPERTY_HEAP_ENTRY HeapEntry;
|
|
|
|
ULONG i;
|
|
|
|
//
|
|
// Map attribute for full size
|
|
//
|
|
|
|
MapPropertyContext( Context );
|
|
|
|
//
|
|
// Verify the property set has valid contents.
|
|
//
|
|
|
|
CheckPropertySet( Context );
|
|
|
|
//
|
|
// Dump out contents of property set
|
|
//
|
|
|
|
DebugTrace( 0, Dbg, ("Property set dump\n") );
|
|
DebugTrace( 0, Dbg, ("wByteOrder %04x wFormat %04x dwOSVer %08x\n",
|
|
Context->Header->wByteOrder,
|
|
Context->Header->wFormat,
|
|
Context->Header->dwOSVer) );
|
|
DebugTrace( 0, Dbg, ("IdTableOffset %08x ValueHeapOffset %08x\n",
|
|
Context->Header->IdTableOffset,
|
|
Context->Header->ValueHeapOffset) );
|
|
|
|
DebugTrace( 0, Dbg, ("IdTable %x/%x entries used\n",
|
|
Context->IdTable->PropertyCount,
|
|
Context->IdTable->MaximumPropertyCount) );
|
|
for (i = 0; i < Context->IdTable->PropertyCount; i++) {
|
|
DebugTrace( 0, Dbg, (" Entry[%d].PropertyId %08x .Header %08x\n",
|
|
i,
|
|
Context->IdTable->Entry[i].PropertyId,
|
|
Context->IdTable->Entry[i].PropertyValueOffset) );
|
|
}
|
|
|
|
|
|
DebugTrace( 0, Dbg, ("PropertyHeapLength %08x\n",
|
|
Context->HeapHeader->PropertyHeapLength) );
|
|
|
|
HeapEntry = FIRST_HEAP_ENTRY( Context->HeapHeader );
|
|
while (!IS_LAST_HEAP_ENTRY( Context->HeapHeader, HeapEntry )) {
|
|
DebugTrace( 0, Dbg, (" Heap[%08x].Length %08x .PropertyId %08x .PropertyNameLength %04x\n",
|
|
HeapOffset( Context, HeapEntry ),
|
|
HeapEntry->PropertyValueLength,
|
|
HeapEntry->PropertyId,
|
|
HeapEntry->PropertyNameLength) );
|
|
DebugTrace( 0, Dbg, (" .PropertyName '%.*ws'\n",
|
|
HeapEntry->PropertyNameLength / sizeof( WCHAR ),
|
|
HeapEntry->PropertyName) );
|
|
HeapEntry = NEXT_HEAP_ENTRY( HeapEntry );
|
|
}
|
|
|
|
}
|
|
|