1318da0c1SPierre Schweitzer /*
2318da0c1SPierre Schweitzer * PROJECT: ReactOS Kernel - Vista+ APIs
3318da0c1SPierre Schweitzer * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4318da0c1SPierre Schweitzer * FILE: lib/drivers/ntoskrnl_vista/fsrtl.c
5318da0c1SPierre Schweitzer * PURPOSE: FsRtl functions of Vista+
6318da0c1SPierre Schweitzer * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
7318da0c1SPierre Schweitzer */
8318da0c1SPierre Schweitzer
9318da0c1SPierre Schweitzer #include <ntifs.h>
10318da0c1SPierre Schweitzer #include <ntdef.h>
11318da0c1SPierre Schweitzer
12318da0c1SPierre Schweitzer FORCEINLINE
13318da0c1SPierre Schweitzer BOOLEAN
IsNullGuid(IN PGUID Guid)14318da0c1SPierre Schweitzer IsNullGuid(IN PGUID Guid)
15318da0c1SPierre Schweitzer {
16318da0c1SPierre Schweitzer if (Guid->Data1 == 0 && Guid->Data2 == 0 && Guid->Data3 == 0 &&
17318da0c1SPierre Schweitzer ((ULONG *)Guid->Data4)[0] == 0 && ((ULONG *)Guid->Data4)[1] == 0)
18318da0c1SPierre Schweitzer {
19318da0c1SPierre Schweitzer return TRUE;
20318da0c1SPierre Schweitzer }
21318da0c1SPierre Schweitzer
22318da0c1SPierre Schweitzer return FALSE;
23318da0c1SPierre Schweitzer }
24318da0c1SPierre Schweitzer
25318da0c1SPierre Schweitzer FORCEINLINE
26318da0c1SPierre Schweitzer BOOLEAN
IsEven(IN USHORT Digit)27318da0c1SPierre Schweitzer IsEven(IN USHORT Digit)
28318da0c1SPierre Schweitzer {
29318da0c1SPierre Schweitzer return ((Digit & 1) != 1);
30318da0c1SPierre Schweitzer }
31318da0c1SPierre Schweitzer
compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength,IN PREPARSE_DATA_BUFFER ReparseBuffer)32*62e630deSPierre Schweitzer NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer)
33318da0c1SPierre Schweitzer {
34318da0c1SPierre Schweitzer USHORT DataLength;
35318da0c1SPierre Schweitzer ULONG ReparseTag;
36318da0c1SPierre Schweitzer PREPARSE_GUID_DATA_BUFFER GuidBuffer;
37318da0c1SPierre Schweitzer
38318da0c1SPierre Schweitzer /* Validate data size range */
39318da0c1SPierre Schweitzer if (BufferLength < REPARSE_DATA_BUFFER_HEADER_SIZE || BufferLength > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
40318da0c1SPierre Schweitzer {
41318da0c1SPierre Schweitzer return STATUS_IO_REPARSE_DATA_INVALID;
42318da0c1SPierre Schweitzer }
43318da0c1SPierre Schweitzer
44318da0c1SPierre Schweitzer GuidBuffer = (PREPARSE_GUID_DATA_BUFFER)ReparseBuffer;
45318da0c1SPierre Schweitzer DataLength = ReparseBuffer->ReparseDataLength;
46318da0c1SPierre Schweitzer ReparseTag = ReparseBuffer->ReparseTag;
47318da0c1SPierre Schweitzer
48318da0c1SPierre Schweitzer /* Validate size consistency */
49318da0c1SPierre Schweitzer if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE != BufferLength && DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE != BufferLength)
50318da0c1SPierre Schweitzer {
51318da0c1SPierre Schweitzer return STATUS_IO_REPARSE_DATA_INVALID;
52318da0c1SPierre Schweitzer }
53318da0c1SPierre Schweitzer
54318da0c1SPierre Schweitzer /* REPARSE_DATA_BUFFER is reserved for MS tags */
55318da0c1SPierre Schweitzer if (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE == BufferLength && !IsReparseTagMicrosoft(ReparseTag))
56318da0c1SPierre Schweitzer {
57318da0c1SPierre Schweitzer return STATUS_IO_REPARSE_DATA_INVALID;
58318da0c1SPierre Schweitzer }
59318da0c1SPierre Schweitzer
60318da0c1SPierre Schweitzer /* If that a GUID data buffer, its GUID cannot be null, and it cannot contain a MS tag */
61318da0c1SPierre Schweitzer if (DataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE == BufferLength && ((!IsReparseTagMicrosoft(ReparseTag)
62318da0c1SPierre Schweitzer && IsNullGuid(&GuidBuffer->ReparseGuid)) || (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT || ReparseTag == IO_REPARSE_TAG_SYMLINK)))
63318da0c1SPierre Schweitzer {
64318da0c1SPierre Schweitzer return STATUS_IO_REPARSE_DATA_INVALID;
65318da0c1SPierre Schweitzer }
66318da0c1SPierre Schweitzer
67318da0c1SPierre Schweitzer /* Check the data for MS non reserved tags */
68318da0c1SPierre Schweitzer if (!(ReparseTag & 0xFFF0000) && ReparseTag != IO_REPARSE_TAG_RESERVED_ZERO && ReparseTag != IO_REPARSE_TAG_RESERVED_ONE)
69318da0c1SPierre Schweitzer {
70318da0c1SPierre Schweitzer /* If that's a mount point, validate the MountPointReparseBuffer branch */
71318da0c1SPierre Schweitzer if (ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
72318da0c1SPierre Schweitzer {
73318da0c1SPierre Schweitzer /* We need information */
74318da0c1SPierre Schweitzer if (DataLength >= REPARSE_DATA_BUFFER_HEADER_SIZE)
75318da0c1SPierre Schweitzer {
76318da0c1SPierre Schweitzer /* Substitue must be the first in row */
77318da0c1SPierre Schweitzer if (!ReparseBuffer->MountPointReparseBuffer.SubstituteNameOffset)
78318da0c1SPierre Schweitzer {
79318da0c1SPierre Schweitzer /* Substitude must be null-terminated */
80318da0c1SPierre Schweitzer if (ReparseBuffer->MountPointReparseBuffer.PrintNameOffset == ReparseBuffer->MountPointReparseBuffer.SubstituteNameLength + sizeof(UNICODE_NULL))
81318da0c1SPierre Schweitzer {
82318da0c1SPierre Schweitzer /* There must just be the Offset/Length fields + buffer + 2 null chars */
83318da0c1SPierre Schweitzer 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))
84318da0c1SPierre Schweitzer {
85318da0c1SPierre Schweitzer return STATUS_SUCCESS;
86318da0c1SPierre Schweitzer }
87318da0c1SPierre Schweitzer }
88318da0c1SPierre Schweitzer }
89318da0c1SPierre Schweitzer }
90318da0c1SPierre Schweitzer }
91318da0c1SPierre Schweitzer else
92318da0c1SPierre Schweitzer {
93318da0c1SPierre Schweitzer #define FIELDS_SIZE (FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset))
94318da0c1SPierre Schweitzer
95318da0c1SPierre Schweitzer /* If that's not a symlink, accept the MS tag as it */
96318da0c1SPierre Schweitzer if (ReparseTag != IO_REPARSE_TAG_SYMLINK)
97318da0c1SPierre Schweitzer {
98318da0c1SPierre Schweitzer return STATUS_SUCCESS;
99318da0c1SPierre Schweitzer }
100318da0c1SPierre Schweitzer
101318da0c1SPierre Schweitzer /* We need information */
102318da0c1SPierre Schweitzer if (DataLength >= FIELDS_SIZE)
103318da0c1SPierre Schweitzer {
104318da0c1SPierre Schweitzer /* Validate lengths */
105318da0c1SPierre Schweitzer if (ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength && ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength)
106318da0c1SPierre Schweitzer {
107318da0c1SPierre Schweitzer /* Validate unicode strings */
108318da0c1SPierre Schweitzer if (IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength) &&
109318da0c1SPierre Schweitzer IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset) && IsEven(ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset))
110318da0c1SPierre Schweitzer {
111318da0c1SPierre Schweitzer if ((DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset + ReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE)
112318da0c1SPierre Schweitzer && (DataLength + REPARSE_DATA_BUFFER_HEADER_SIZE >= ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength + ReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset + FIELDS_SIZE + REPARSE_DATA_BUFFER_HEADER_SIZE))
113318da0c1SPierre Schweitzer {
114318da0c1SPierre Schweitzer return STATUS_SUCCESS;
115318da0c1SPierre Schweitzer }
116318da0c1SPierre Schweitzer }
117318da0c1SPierre Schweitzer }
118318da0c1SPierre Schweitzer }
119318da0c1SPierre Schweitzer #undef FIELDS_SIZE
120318da0c1SPierre Schweitzer }
121318da0c1SPierre Schweitzer
122318da0c1SPierre Schweitzer return STATUS_IO_REPARSE_DATA_INVALID;
123318da0c1SPierre Schweitzer }
124318da0c1SPierre Schweitzer
125318da0c1SPierre Schweitzer return STATUS_IO_REPARSE_TAG_INVALID;
126318da0c1SPierre Schweitzer }
127