xref: /reactos/sdk/include/reactos/probe.h (revision f59c58d8)
1 #ifndef INCLUDE_REACTOS_CAPTURE_H
2 #define INCLUDE_REACTOS_CAPTURE_H
3 
4 #include <suppress.h>
5 
6 #if ! defined(_NTOSKRNL_) && ! defined(_WIN32K_)
7 #error Header intended for use by NTOSKRNL/WIN32K only!
8 #endif
9 
10 static const UNICODE_STRING __emptyUnicodeString = {0, 0, NULL};
11 static const LARGE_INTEGER __emptyLargeInteger = {{0, 0}};
12 static const ULARGE_INTEGER __emptyULargeInteger = {{0, 0}};
13 static const IO_STATUS_BLOCK __emptyIoStatusBlock = {{0}, 0};
14 
15 #if defined(_WIN32K_) && !defined(__cplusplus)
16 static const LARGE_STRING __emptyLargeString = {0, 0, 0, NULL};
17 #endif
18 
19 /*
20  * NOTE: Alignment of the pointers is not verified!
21  */
22 #define ProbeForWriteGenericType(Ptr, Type)                                    \
23     do {                                                                       \
24         if ((ULONG_PTR)(Ptr) + sizeof(Type) - 1 < (ULONG_PTR)(Ptr) ||          \
25             (ULONG_PTR)(Ptr) + sizeof(Type) - 1 >= (ULONG_PTR)MmUserProbeAddress) { \
26             ExRaiseAccessViolation();                                          \
27         }                                                                      \
28         *(volatile Type *)(Ptr) = *(volatile Type *)(Ptr);                     \
29     } while (0)
30 
31 #define ProbeForWriteBoolean(Ptr) ProbeForWriteGenericType(Ptr, BOOLEAN)
32 #define ProbeForWriteUchar(Ptr) ProbeForWriteGenericType(Ptr, UCHAR)
33 #define ProbeForWriteChar(Ptr) ProbeForWriteGenericType(Ptr, CHAR)
34 #define ProbeForWriteUshort(Ptr) ProbeForWriteGenericType(Ptr, USHORT)
35 #define ProbeForWriteShort(Ptr) ProbeForWriteGenericType(Ptr, SHORT)
36 #define ProbeForWriteUlong(Ptr) ProbeForWriteGenericType(Ptr, ULONG)
37 #define ProbeForWriteLong(Ptr) ProbeForWriteGenericType(Ptr, LONG)
38 #define ProbeForWriteUint(Ptr) ProbeForWriteGenericType(Ptr, UINT)
39 #define ProbeForWriteInt(Ptr) ProbeForWriteGenericType(Ptr, INT)
40 #define ProbeForWriteUlonglong(Ptr) ProbeForWriteGenericType(Ptr, ULONGLONG)
41 #define ProbeForWriteLonglong(Ptr) ProbeForWriteGenericType(Ptr, LONGLONG)
42 #define ProbeForWritePointer(Ptr) ProbeForWriteGenericType(Ptr, PVOID)
43 #define ProbeForWriteHandle(Ptr) ProbeForWriteGenericType(Ptr, HANDLE)
44 #define ProbeForWriteLangId(Ptr) ProbeForWriteGenericType(Ptr, LANGID)
45 #define ProbeForWriteSize_t(Ptr) ProbeForWriteGenericType(Ptr, SIZE_T)
46 #define ProbeForWriteLargeInteger(Ptr) ProbeForWriteGenericType(&((PLARGE_INTEGER)Ptr)->QuadPart, LONGLONG)
47 #define ProbeForWriteUlargeInteger(Ptr) ProbeForWriteGenericType(&((PULARGE_INTEGER)Ptr)->QuadPart, ULONGLONG)
48 #define ProbeForWriteUnicodeString(Ptr) ProbeForWriteGenericType((PUNICODE_STRING)Ptr, UNICODE_STRING)
49 #if defined(_WIN32K_)
50 #define ProbeForWriteLargeString(Ptr) ProbeForWriteGenericType((PLARGE_STRING)Ptr, LARGE_STRING)
51 #endif
52 #define ProbeForWriteIoStatusBlock(Ptr) ProbeForWriteGenericType((PIO_STATUS_BLOCK)Ptr, IO_STATUS_BLOCK)
53 
54 #define ProbeForReadGenericType(Ptr, Type, Default)                            \
55     (((ULONG_PTR)(Ptr) + sizeof(Type) - 1 < (ULONG_PTR)(Ptr) ||                \
56      (ULONG_PTR)(Ptr) + sizeof(Type) - 1 >= (ULONG_PTR)MmUserProbeAddress) ?   \
57          ExRaiseAccessViolation(), Default :                     \
58          *(const volatile Type *)(Ptr))
59 
60 #define ProbeForReadBoolean(Ptr) ProbeForReadGenericType(Ptr, BOOLEAN, FALSE)
61 #define ProbeForReadUchar(Ptr) ProbeForReadGenericType(Ptr, UCHAR, 0)
62 #define ProbeForReadChar(Ptr) ProbeForReadGenericType(Ptr, CHAR, 0)
63 #define ProbeForReadUshort(Ptr) ProbeForReadGenericType(Ptr, USHORT, 0)
64 #define ProbeForReadShort(Ptr) ProbeForReadGenericType(Ptr, SHORT, 0)
65 #define ProbeForReadUlong(Ptr) ProbeForReadGenericType(Ptr, ULONG, 0)
66 #define ProbeForReadLong(Ptr) ProbeForReadGenericType(Ptr, LONG, 0)
67 #define ProbeForReadUint(Ptr) ProbeForReadGenericType(Ptr, UINT, 0)
68 #define ProbeForReadInt(Ptr) ProbeForReadGenericType(Ptr, INT, 0)
69 #define ProbeForReadUlonglong(Ptr) ProbeForReadGenericType(Ptr, ULONGLONG, 0)
70 #define ProbeForReadLonglong(Ptr) ProbeForReadGenericType(Ptr, LONGLONG, 0)
71 #define ProbeForReadPointer(Ptr) ProbeForReadGenericType(Ptr, PVOID, NULL)
72 #define ProbeForReadHandle(Ptr) ProbeForReadGenericType(Ptr, HANDLE, NULL)
73 #define ProbeForReadLangId(Ptr) ProbeForReadGenericType(Ptr, LANGID, 0)
74 #define ProbeForReadSize_t(Ptr) ProbeForReadGenericType(Ptr, SIZE_T, 0)
75 #define ProbeForReadLargeInteger(Ptr) ProbeForReadGenericType((const LARGE_INTEGER *)(Ptr), LARGE_INTEGER, __emptyLargeInteger)
76 #define ProbeForReadUlargeInteger(Ptr) ProbeForReadGenericType((const ULARGE_INTEGER *)(Ptr), ULARGE_INTEGER, __emptyULargeInteger)
77 #define ProbeForReadUnicodeString(Ptr) ProbeForReadGenericType((const UNICODE_STRING *)(Ptr), UNICODE_STRING, __emptyUnicodeString)
78 #if defined(_WIN32K_)
79 #define ProbeForReadLargeString(Ptr) ProbeForReadGenericType((const LARGE_STRING *)(Ptr), LARGE_STRING, __emptyLargeString)
80 #endif
81 #define ProbeForReadIoStatusBlock(Ptr) ProbeForReadGenericType((const IO_STATUS_BLOCK *)(Ptr), IO_STATUS_BLOCK, __emptyIoStatusBlock)
82 
83 #define ProbeAndZeroHandle(Ptr) \
84     do {                                                                       \
85         if ((ULONG_PTR)(Ptr) + sizeof(HANDLE) - 1 < (ULONG_PTR)(Ptr) ||        \
86             (ULONG_PTR)(Ptr) + sizeof(HANDLE) - 1 >= (ULONG_PTR)MmUserProbeAddress) { \
87             ExRaiseAccessViolation();                                          \
88         }                                                                      \
89         *(volatile HANDLE *)(Ptr) = NULL;                                      \
90     } while (0)
91 
92 /*
93  * Inlined Probing Macros
94  */
95 
96 #if defined(_WIN32K_)
97 static __inline
98 VOID
99 ProbeArrayForRead(IN const VOID *ArrayPtr,
100                   IN ULONG ItemSize,
101                   IN ULONG ItemCount,
102                   IN ULONG Alignment)
103 {
104     ULONG ArraySize;
105 
106     /* Check for integer overflow */
107     ArraySize = ItemSize * ItemCount;
108     if (ArraySize / ItemSize != ItemCount)
109     {
110         ExRaiseStatus(STATUS_INVALID_PARAMETER);
111     }
112 
113     /* Probe the array */
114     _PRAGMA_WARNING_SUPPRESS(__WARNING_PROBE_NO_TRY) /* Must be inside __try / __except block */
115     ProbeForRead(ArrayPtr, ArraySize, Alignment);
116 }
117 
118 static __inline
119 VOID
120 ProbeArrayForWrite(IN OUT PVOID ArrayPtr,
121                    IN ULONG ItemSize,
122                    IN ULONG ItemCount,
123                    IN ULONG Alignment)
124 {
125     ULONG ArraySize;
126 
127     /* Check for integer overflow */
128     ArraySize = ItemSize * ItemCount;
129     if (ArraySize / ItemSize != ItemCount)
130     {
131         ExRaiseStatus(STATUS_INVALID_PARAMETER);
132     }
133 
134     /* Probe the array */
135     _PRAGMA_WARNING_SUPPRESS(__WARNING_PROBE_NO_TRY) /* Must be inside __try / __except block */
136     ProbeForWrite(ArrayPtr, ArraySize, Alignment);
137 }
138 #endif /* _WIN32K_ */
139 
140 static __inline
141 NTSTATUS
142 ProbeAndCaptureUnicodeString(OUT PUNICODE_STRING Dest,
143                              IN KPROCESSOR_MODE CurrentMode,
144                              IN const UNICODE_STRING *UnsafeSrc)
145 {
146     NTSTATUS Status = STATUS_SUCCESS;
147     PWCHAR Buffer = NULL;
148     ASSERT(Dest != NULL);
149 
150     /* Probe the structure and buffer*/
151     if(CurrentMode != KernelMode)
152     {
153         _SEH2_TRY
154         {
155 #ifdef __cplusplus
156             ProbeForRead(UnsafeSrc, sizeof(*UnsafeSrc), 1);
157             RtlCopyMemory(Dest, UnsafeSrc, sizeof(*UnsafeSrc));
158 #else
159             *Dest = ProbeForReadUnicodeString(UnsafeSrc);
160 #endif
161             if(Dest->Buffer != NULL)
162             {
163                 if (Dest->Length != 0)
164                 {
165                     ProbeForRead(Dest->Buffer, Dest->Length, sizeof(WCHAR));
166 
167                     /* Allocate space for the buffer */
168                     Buffer = (PWCHAR)ExAllocatePoolWithTag(PagedPool,
169                                                    Dest->Length + sizeof(WCHAR),
170                                                    'RTSU');
171                     if (Buffer == NULL)
172                     {
173                         Status = STATUS_INSUFFICIENT_RESOURCES;
174                         _SEH2_LEAVE;
175                     }
176 
177                     /* Copy it */
178                     RtlCopyMemory(Buffer, Dest->Buffer, Dest->Length);
179                     Buffer[Dest->Length / sizeof(WCHAR)] = UNICODE_NULL;
180 
181                     /* Set it as the buffer */
182                     Dest->Buffer = Buffer;
183                     if (Dest->Length % sizeof(WCHAR))
184                     {
185                         Dest->Length--;
186                     }
187                     if (Dest->Length >= UNICODE_STRING_MAX_BYTES)
188                     {
189                         Dest->MaximumLength = Dest->Length;
190                     }
191                     else
192                     {
193                         Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
194                     }
195                 }
196                 else
197                 {
198                     /* Sanitize structure */
199                     Dest->MaximumLength = 0;
200                     Dest->Buffer = NULL;
201                 }
202             }
203             else
204             {
205                 /* Sanitize structure */
206                 Dest->Length = 0;
207                 Dest->MaximumLength = 0;
208             }
209         }
210         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
211         {
212             /* Free allocated resources and zero the destination string */
213             if (Buffer != NULL)
214             {
215                 ExFreePoolWithTag(Buffer, 'RTSU');
216             }
217             Dest->Length = 0;
218             Dest->MaximumLength = 0;
219             Dest->Buffer = NULL;
220 
221             /* Return the error code */
222             Status = _SEH2_GetExceptionCode();
223         }
224         _SEH2_END;
225     }
226     else
227     {
228         /* Just copy the UNICODE_STRING structure, don't allocate new memory!
229            We trust the caller to supply valid pointers and data. */
230         *Dest = *UnsafeSrc;
231     }
232 
233     /* Return */
234     return Status;
235 }
236 
237 static __inline
238 VOID
239 ReleaseCapturedUnicodeString(IN PUNICODE_STRING CapturedString,
240                              IN KPROCESSOR_MODE CurrentMode)
241 {
242     if(CurrentMode != KernelMode && CapturedString->Buffer != NULL)
243     {
244         ExFreePoolWithTag(CapturedString->Buffer, 'RTSU');
245     }
246 
247     CapturedString->Length = 0;
248     CapturedString->MaximumLength = 0;
249     CapturedString->Buffer = NULL;
250 }
251 
252 #endif /* INCLUDE_REACTOS_CAPTURE_H */
253