From c6967c737a1e52068d2884907de4bf642bade7c9 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 5 Oct 2016 13:44:32 -0700 Subject: [PATCH] sys: FspUnicodePathIsValid: check and return stream type --- src/sys/create.c | 17 +++++++++++++++-- src/sys/driver.h | 7 ++++++- src/sys/file.c | 2 +- src/sys/fileinfo.c | 4 ++-- src/sys/util.c | 45 +++++++++++++++++++++++++++++++++++++-------- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/sys/create.c b/src/sys/create.c index 949f24c1..3d79078a 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -179,6 +179,7 @@ static NTSTATUS FspFsvolCreateNoLock( FSP_FILE_NODE *FileNode, *RelatedFileNode; FSP_FILE_DESC *FileDesc; UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 }; + ULONG StreamType = FspUnicodePathStreamTypeNone; FSP_FSCTL_TRANSACT_REQ *Request; /* cannot open files by fileid */ @@ -276,7 +277,8 @@ static NTSTATUS FspFsvolCreateNoLock( /* check filename validity */ if (!FspUnicodePathIsValid(&FileNode->FileName, - FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0)) + FsvolDeviceExtension->VolumeParams.NamedStreams ? &StreamPart : 0, + &StreamType)) { FspFileNodeDereference(FileNode); return STATUS_OBJECT_NAME_INVALID; @@ -291,7 +293,8 @@ static NTSTATUS FspFsvolCreateNoLock( (PUINT8)FileNode->FileName.Buffer + FileNode->FileName.Length); FileNode->FileName.Length = (USHORT) - ((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer + StreamPart.Length); + ((PUINT8)StreamPart.Buffer - (PUINT8)FileNode->FileName.Buffer + StreamPart.Length - + (0 == StreamPart.Length) * sizeof(WCHAR)); } /* check and remove any volume prefix */ @@ -330,6 +333,16 @@ static NTSTATUS FspFsvolCreateNoLock( FileNode->FileName.Length -= sizeof(WCHAR); } + /* if a $DATA stream type, this cannot be a directory */ + if (FspUnicodePathStreamTypeData == StreamType) + { + if (FlagOn(CreateOptions, FILE_DIRECTORY_FILE)) + { + FspFileNodeDereference(FileNode); + return STATUS_NOT_A_DIRECTORY; + } + } + /* not all operations allowed on the root directory */ if (sizeof(WCHAR) == FileNode->FileName.Length && (FILE_CREATE == CreateDisposition || diff --git a/src/sys/driver.h b/src/sys/driver.h index 40da8934..cc163ef5 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -423,9 +423,14 @@ BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime) } /* utility */ +enum +{ + FspUnicodePathStreamTypeNone = 0, + FspUnicodePathStreamTypeData = 1, +}; PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag); PVOID FspAllocateIrpMustSucceed(CCHAR StackSize); -BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart); +BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType); BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern); VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); NTSTATUS FspCreateGuid(GUID *Guid); diff --git a/src/sys/file.c b/src/sys/file.c index a7e3aa9d..52bf81f0 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -1274,7 +1274,7 @@ NTSTATUS FspMainFileOpen( PFILE_OBJECT MainFileObject; /* assert that the supplied name is actually a main file name */ - ASSERT(FspUnicodePathIsValid(MainFileName, 0)); + ASSERT(FspUnicodePathIsValid(MainFileName, 0, 0)); *PMainFileHandle = 0; *PMainFileObject = 0; diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index d28cb3be..e0ec1fec 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -1114,7 +1114,7 @@ static NTSTATUS FspFsvolSetRenameInformation( if (FileNode->IsRootDirectory) /* cannot rename root directory */ return STATUS_INVALID_PARAMETER; - if (!FspUnicodePathIsValid(&FileNode->FileName, 0)) + if (!FspUnicodePathIsValid(&FileNode->FileName, 0, 0)) /* cannot rename streams (WinFsp limitation) */ return STATUS_INVALID_PARAMETER; @@ -1139,7 +1139,7 @@ static NTSTATUS FspFsvolSetRenameInformation( if (L'\\' == Suffix.Buffer[0]) FspUnicodePathSuffix(&Suffix, &NewFileName, &Suffix); - if (!FspUnicodePathIsValid(&Remain, 0) || !FspUnicodePathIsValid(&Suffix, 0)) + if (!FspUnicodePathIsValid(&Remain, 0, 0) || !FspUnicodePathIsValid(&Suffix, 0, 0)) { /* cannot rename streams (WinFsp limitation) */ Result = STATUS_INVALID_PARAMETER; diff --git a/src/sys/util.c b/src/sys/util.c index 6cffe1d0..95aa52f6 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -17,7 +17,7 @@ #include -BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart); +BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType); BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern); VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); NTSTATUS FspCreateGuid(GUID *Guid); @@ -171,14 +171,17 @@ PVOID FspAllocateIrpMustSucceed(CCHAR StackSize) } } -BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart) +BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType) { PAGED_CODE(); + /* if StreamPart is not NULL, StreamType must also be not NULL */ + ASSERT(0 == StreamPart || 0 != StreamType); + if (0 != Path->Length % sizeof(WCHAR)) return FALSE; - PWSTR PathBgn, PathEnd, PathPtr; + PWSTR PathBgn, PathEnd, PathPtr, StreamTypeStr = 0; UCHAR Flags = FSRTL_NTFS_LEGAL; ULONG Colons = 0; WCHAR Char; @@ -221,15 +224,17 @@ BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart) if (1 == Colons) { /* first time through: set up StreamPart */ - StreamPart->Length = StreamPart->MaximumLength = - (USHORT)((PUINT8)PathEnd - (PUINT8)PathPtr); + StreamPart->Length = StreamPart->MaximumLength = (USHORT) + ((PUINT8)PathEnd - (PUINT8)PathPtr); StreamPart->Buffer = PathPtr; } else if (2 == Colons) { /* second time through: fix StreamPart length to not include 2nd colon */ - StreamPart->Length = - (USHORT)((PUINT8)PathPtr - (PUINT8)StreamPart->Buffer - 1); + StreamPart->Length = (USHORT) + ((PUINT8)PathPtr - (PUINT8)StreamPart->Buffer - sizeof(WCHAR)); + + StreamTypeStr = PathPtr; } } else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, FALSE, Flags)) @@ -238,7 +243,31 @@ BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart) PathPtr++; } - return TRUE; + /* if we had no colons the path is valid */ + if (0 == Colons) + return TRUE; + + ASSERT(0 != StreamPart && 0 != StreamType); + + *StreamType = FspUnicodePathStreamTypeNone; + + /* if we had no stream type the path is valid if there was an actual stream name */ + if (0 == StreamTypeStr) + return 0 != StreamPart->Length; + + /* if we had a stream type the path is valid if the stream type was "$DATA" only */ + if (StreamTypeStr + 5 == PathEnd && + L'$' == StreamTypeStr[0] && + L'D' == StreamTypeStr[1] && + L'A' == StreamTypeStr[2] && + L'T' == StreamTypeStr[3] && + L'A' == StreamTypeStr[4]) + { + *StreamType = FspUnicodePathStreamTypeData; + return TRUE; + } + + return FALSE; } BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Path)