1 /* 2 * PROJECT: ReactOS Kernel - Vista+ APIs 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * FILE: lib/drivers/ntoskrnl_vista/fsrtl.c 5 * PURPOSE: FsRtl functions of Vista+ 6 * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org> 7 */ 8 9 #include <ntifs.h> 10 #include <ntdef.h> 11 12 FORCEINLINE 13 BOOLEAN 14 IsNullGuid(IN PGUID Guid) 15 { 16 if (Guid->Data1 == 0 && Guid->Data2 == 0 && Guid->Data3 == 0 && 17 ((ULONG *)Guid->Data4)[0] == 0 && ((ULONG *)Guid->Data4)[1] == 0) 18 { 19 return TRUE; 20 } 21 22 return FALSE; 23 } 24 25 FORCEINLINE 26 BOOLEAN 27 IsEven(IN USHORT Digit) 28 { 29 return ((Digit & 1) != 1); 30 } 31 32 NTSTATUS compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer) 33 { 34 USHORT DataLength; 35 ULONG ReparseTag; 36 PREPARSE_GUID_DATA_BUFFER GuidBuffer; 37 38 /* Validate data size range */ 39 if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE || BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE) 40 { 41 return STATUS_IO_REPARSE_DATA_INVALID; 42 } 43 44 GuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer; 45 DataLength = ReparseBuffer->ReparseDataLength; 46 ReparseTag = ReparseBuffer->ReparseTag; 47 48 /* Validate size consistency */ 49 if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE != BufferLength && DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE != BufferLength) 50 { 51 return STATUS_IO_REPARSE_DATA_INVALID; 52 } 53 54 /* REPARSE_DATA_BUFFER is reserved for MS tags */ 55 if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE == BufferLength && !IsReparseTagMicrosoft(ReparseTag)) 56 { 57 return STATUS_IO_REPARSE_DATA_INVALID; 58 } 59 60 /* If that a GUID data buffer, its GUID cannot be null, and it cannot contain a MS tag */ 61 if (DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE == BufferLength && ((!IsReparseTagMicrosoft(ReparseTag) 62 && IsNullGuid(&GuidBuffer->ReparseGuid)) || (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT || ReparseTag == IO_REPARSE_TAG_SYMLINK))) 63 { 64 return STATUS_IO_REPARSE_DATA_INVALID; 65 } 66 67 /* Check the data for MS non reserved tags */ 68 if (!(ReparseTag & 0xFFF0000) && ReparseTag != IO_REPARSE_TAG_RESERVED_ZERO && ReparseTag != IO_REPARSE_TAG_RESERVED_ONE) 69 { 70 /* If that's a mount point, validate the MountPointReparseBuffer branch */ 71 if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) 72 { 73 /* We need information */ 74 if (DataLength >= REPARSE_DATA_BUFFER_HEADER_SIZE) 75 { 76 /* Substitue must be the first in row */ 77 if (!ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset) 78 { 79 /* Substitude must be null-terminated */ 80 if (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset == ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL)) 81 { 82 /* There must just be the Offset/Length fields + buffer + 2 null chars */ 83 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)) 84 { 85 return STATUS_SUCCESS; 86 } 87 } 88 } 89 } 90 } 91 else 92 { 93 #define FIELDS_SIZE (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset)) 94 95 /* If that's not a symlink, accept the MS tag as it */ 96 if (ReparseTag != IO_REPARSE_TAG_SYMLINK) 97 { 98 return STATUS_SUCCESS; 99 } 100 101 /* We need information */ 102 if (DataLength >= FIELDS_SIZE) 103 { 104 /* Validate lengths */ 105 if (ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength && ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) 106 { 107 /* Validate unicode strings */ 108 if (IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) && 109 IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset)) 110 { 111 if ((DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset + ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE) 112 && (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE)) 113 { 114 return STATUS_SUCCESS; 115 } 116 } 117 } 118 } 119 #undef FIELDS_SIZE 120 } 121 122 return STATUS_IO_REPARSE_DATA_INVALID; 123 } 124 125 return STATUS_IO_REPARSE_TAG_INVALID; 126 } 127