Big merge: thanks alex and greatlord. Not a complete merge but most
[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 #if defined(_M_PPC)
9 extern ULONG_PTR MmUserProbeAddress;
10 #endif
11
12 static const UNICODE_STRING __emptyUnicodeString = {0};
13 static const LARGE_INTEGER __emptyLargeInteger = {{0, 0}};
14 static const ULARGE_INTEGER __emptyULargeInteger = {{0, 0}};
15 static const IO_STATUS_BLOCK __emptyIoStatusBlock = {{0}, 0};
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 #define ProbeForWriteIoStatusBlock(Ptr) ProbeForWriteGenericType((PIO_STATUS_BLOCK)Ptr, IO_STATUS_BLOCK)
56
57 #define ProbeForReadGenericType(Ptr, Type, Default) \
58 (((ULONG_PTR)(Ptr) + sizeof(Type) - 1 < (ULONG_PTR)(Ptr) || \
59 (ULONG_PTR)(Ptr) + sizeof(Type) - 1 >= (ULONG_PTR)MmUserProbeAddress) ? \
60 ExRaiseStatus (STATUS_ACCESS_VIOLATION), Default : \
61 *(const volatile Type *)(Ptr))
62
63 #define ProbeForReadBoolean(Ptr) ProbeForReadGenericType(Ptr, BOOLEAN, FALSE)
64 #define ProbeForReadUchar(Ptr) ProbeForReadGenericType(Ptr, UCHAR, 0)
65 #define ProbeForReadChar(Ptr) ProbeForReadGenericType(Ptr, CHAR, 0)
66 #define ProbeForReadUshort(Ptr) ProbeForReadGenericType(Ptr, USHORT, 0)
67 #define ProbeForReadShort(Ptr) ProbeForReadGenericType(Ptr, SHORT, 0)
68 #define ProbeForReadUlong(Ptr) ProbeForReadGenericType(Ptr, ULONG, 0)
69 #define ProbeForReadLong(Ptr) ProbeForReadGenericType(Ptr, LONG, 0)
70 #define ProbeForReadUint(Ptr) ProbeForReadGenericType(Ptr, UINT, 0)
71 #define ProbeForReadInt(Ptr) ProbeForReadGenericType(Ptr, INT, 0)
72 #define ProbeForReadUlonglong(Ptr) ProbeForReadGenericType(Ptr, ULONGLONG, 0)
73 #define ProbeForReadLonglong(Ptr) ProbeForReadGenericType(Ptr, LONGLONG, 0)
74 #define ProbeForReadPointer(Ptr) ProbeForReadGenericType(Ptr, PVOID, NULL)
75 #define ProbeForReadHandle(Ptr) ProbeForReadGenericType(Ptr, HANDLE, NULL)
76 #define ProbeForReadLangid(Ptr) ProbeForReadGenericType(Ptr, LANGID, 0)
77 #define ProbeForReadSize_t(Ptr) ProbeForReadGenericType(Ptr, SIZE_T, 0)
78 #define ProbeForReadLargeInteger(Ptr) ProbeForReadGenericType((const LARGE_INTEGER *)(Ptr), LARGE_INTEGER, __emptyLargeInteger)
79 #define ProbeForReadUlargeInteger(Ptr) ProbeForReadGenericType((const ULARGE_INTEGER *)(Ptr), ULARGE_INTEGER, __emptyULargeInteger)
80 #define ProbeForReadUnicodeString(Ptr) ProbeForReadGenericType((const UNICODE_STRING *)(Ptr), UNICODE_STRING, __emptyUnicodeString)
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 RtlRaiseStatus (STATUS_ACCESS_VIOLATION); \
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 NTAPI
100 ProbeArrayForRead(IN const VOID *ArrayPtr,
101 IN ULONG ItemSize,
102 IN ULONG ItemCount,
103 IN ULONG Alignment)
104 {
105 ULONG ArraySize;
106
107 /* Check for integer overflow */
108 ArraySize = ItemSize * ItemCount;
109 if (ArraySize / ItemSize != ItemCount)
110 {
111 RtlRaiseStatus (STATUS_INVALID_PARAMETER);
112 }
113
114 /* Probe the array */
115 ProbeForRead(ArrayPtr,
116 ArraySize,
117 Alignment);
118 }
119
120 static __inline
121 VOID
122 NTAPI
123 ProbeArrayForWrite(IN OUT PVOID ArrayPtr,
124 IN ULONG ItemSize,
125 IN ULONG ItemCount,
126 IN ULONG Alignment)
127 {
128 ULONG ArraySize;
129
130 /* Check for integer overflow */
131 ArraySize = ItemSize * ItemCount;
132 if (ArraySize / ItemSize != ItemCount)
133 {
134 RtlRaiseStatus (STATUS_INVALID_PARAMETER);
135 }
136
137 /* Probe the array */
138 ProbeForWrite(ArrayPtr,
139 ArraySize,
140 Alignment);
141 }
142 #endif /* _WIN32K_ */
143
144 static __inline
145 NTSTATUS
146 NTAPI
147 ProbeAndCaptureUnicodeString(OUT PUNICODE_STRING Dest,
148 IN KPROCESSOR_MODE CurrentMode,
149 IN const UNICODE_STRING *UnsafeSrc)
150 {
151 NTSTATUS Status = STATUS_SUCCESS;
152 WCHAR *Buffer = NULL;
153 ASSERT(Dest != NULL);
154
155 /* Probe the structure and buffer*/
156 if(CurrentMode != KernelMode)
157 {
158 _SEH_TRY
159 {
160 *Dest = ProbeForReadUnicodeString(UnsafeSrc);
161 if(Dest->Buffer != NULL)
162 {
163 if (Dest->Length != 0)
164 {
165 ProbeForRead(Dest->Buffer,
166 Dest->Length,
167 sizeof(WCHAR));
168
169 /* Allocate space for the buffer */
170 Buffer = ExAllocatePoolWithTag(PagedPool,
171 Dest->Length + sizeof(WCHAR),
172 TAG('U', 'S', 'T', 'R'));
173 if (Buffer == NULL)
174 {
175 Status = STATUS_INSUFFICIENT_RESOURCES;
176 _SEH_LEAVE;
177 }
178
179 /* Copy it */
180 RtlCopyMemory(Buffer, Dest->Buffer, Dest->Length);
181 Buffer[Dest->Length / sizeof(WCHAR)] = UNICODE_NULL;
182
183 /* Set it as the buffer */
184 Dest->Buffer = Buffer;
185 Dest->MaximumLength = Dest->Length + sizeof(WCHAR);
186 }
187 else
188 {
189 /* sanitize structure */
190 Dest->MaximumLength = 0;
191 Dest->Buffer = NULL;
192 }
193 }
194 else
195 {
196 /* sanitize structure */
197 Dest->Length = 0;
198 Dest->MaximumLength = 0;
199 }
200 }
201 _SEH_HANDLE
202 {
203 /* Free allocated resources and zero the destination string */
204 if (Buffer != NULL)
205 {
206 ExFreePool(Buffer);
207 }
208 Dest->Length = 0;
209 Dest->MaximumLength = 0;
210 Dest->Buffer = NULL;
211
212 /* Return the error code */
213 Status = _SEH_GetExceptionCode();
214 }
215 _SEH_END;
216 }
217 else
218 {
219 /* Just copy the UNICODE_STRING structure, don't allocate new memory!
220 We trust the caller to supply valid pointers and data. */
221 *Dest = *UnsafeSrc;
222 }
223
224 /* Return */
225 return Status;
226 }
227
228 static __inline
229 VOID
230 NTAPI
231 ReleaseCapturedUnicodeString(IN PUNICODE_STRING CapturedString,
232 IN KPROCESSOR_MODE CurrentMode)
233 {
234 if(CurrentMode != KernelMode && CapturedString->Buffer != NULL)
235 {
236 ExFreePool(CapturedString->Buffer);
237 }
238 }
239
240 #endif /* INCLUDE_REACTOS_CAPTURE_H */