/*++ Copyright (c) 1989-1997 Microsoft Corporation Module Name: check.c Abstract: This module contains the property set check support --*/ #include // 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 ); } }