Author: pschweitzer Date: Thu May 5 16:58:16 2016 New Revision: 71264 URL: http://svn.reactos.org/svn/reactos?rev=71264&view=rev Log: [NTOSKRNL_VISTA] Implement FsRtlValidateReparsePointBuffer().
CORE-11172 Modified: trunk/reactos/sdk/lib/drivers/ntoskrnl_vista/fsrtl.c Modified: trunk/reactos/sdk/lib/drivers/ntoskrnl_vista/fsrtl.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/drivers/ntoskrnl_vista/fsrtl.c?rev=71264&r1=71263&r2=71264&view=diff ============================================================================== --- trunk/reactos/sdk/lib/drivers/ntoskrnl_vista/fsrtl.c [iso-8859-1] (original) +++ trunk/reactos/sdk/lib/drivers/ntoskrnl_vista/fsrtl.c [iso-8859-1] Thu May 5 16:58:16 2016 @@ -119,3 +119,124 @@ return STATUS_SUCCESS; } + +FORCEINLINE +BOOLEAN +IsNullGuid(IN PGUID Guid) +{ + if (Guid->Data1 == 0 && Guid->Data2 == 0 && Guid->Data3 == 0 && + ((ULONG *)Guid->Data4)[0] == 0 && ((ULONG *)Guid->Data4)[1] == 0) + { + return TRUE; + } + + return FALSE; +} + +FORCEINLINE +BOOLEAN +IsEven(IN USHORT Digit) +{ + return ((Digit & 1) != 1); +} + +NTKERNELAPI +NTSTATUS +NTAPI +FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, + IN PREPARSE_DATA_BUFFER ReparseBuffer) +{ + USHORT DataLength; + ULONG ReparseTag; + PREPARSE_GUID_DATA_BUFFER GuidBuffer; + + /* Validate data size range */ + if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE || BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) + { + return STATUS_IO_REPARSE_DATA_INVALID; + } + + GuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer; + DataLength = ReparseBuffer->ReparseDataLength; + ReparseTag = ReparseBuffer->ReparseTag; + + /* Validate size consistency */ + if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE != BufferLength && DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE != BufferLength) + { + return STATUS_IO_REPARSE_DATA_INVALID; + } + + /* REPARSE_DATA_BUFFER is reserved for MS tags */ + if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE == BufferLength && !IsReparseTagMicrosoft(ReparseTag)) + { + return STATUS_IO_REPARSE_DATA_INVALID; + } + + /* If that a GUID data buffer, its GUID cannot be null, and it cannot contain a MS tag */ + if (DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE == BufferLength && ((!IsReparseTagMicrosoft(ReparseTag) + && IsNullGuid(&GuidBuffer->ReparseGuid)) || (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT || ReparseTag == IO_REPARSE_TAG_SYMLINK))) + { + return STATUS_IO_REPARSE_DATA_INVALID; + } + + /* Check the data for MS non reserved tags */ + if (!(ReparseTag & 0xFFF0000) && ReparseTag != IO_REPARSE_TAG_RESERVED_ZERO && ReparseTag != IO_REPARSE_TAG_RESERVED_ONE) + { + /* If that's a mount point, validate the MountPointReparseBuffer branch */ + if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) + { + /* We need information */ + if (DataLength >= REPARSE_DATA_BUFFER_HEADER_SIZE) + { + /* Substitue must be the first in row */ + if (!ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset) + { + /* Substitude must be null-terminated */ + if (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset == ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL)) + { + /* There must just be the Offset/Length fields + buffer + 2 null chars */ + if (DataLength == ReparseBuffer->MountPointReparseBuffer.PrintNameLength + ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + (FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.SubstituteNameOffset)) + 2 * sizeof(UNICODE_NULL)) + { + return STATUS_SUCCESS; + } + } + } + } + } + else + { +#define FIELDS_SIZE (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset)) + + /* If that's not a symlink, accept the MS tag as it */ + if (ReparseTag != IO_REPARSE_TAG_SYMLINK) + { + return STATUS_SUCCESS; + } + + /* We need information */ + if (DataLength >= FIELDS_SIZE) + { + /* Validate lengths */ + if (ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength && ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) + { + /* Validate unicode strings */ + if (IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) && + IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset)) + { + if ((DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset + ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE) + && (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE)) + { + return STATUS_SUCCESS; + } + } + } + } +#undef FIELDS_SIZE + } + + return STATUS_IO_REPARSE_DATA_INVALID; + } + + return STATUS_IO_REPARSE_TAG_INVALID; +} +