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