1 /*
2 * PROJECT: ReactOS Client/Server Runtime SubSystem
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: CSR Client Library - CSR API Messages probing and capturing
5 * COPYRIGHT: Copyright 2005 Alex Ionescu <alex@relsoft.net>
6 * Copyright 2012-2022 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "csrlib.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS ******************************************************************/
17
18 /*
19 * @implemented
20 */
21 VOID
22 NTAPI
CsrProbeForRead(_In_ PVOID Address,_In_ ULONG Length,_In_ ULONG Alignment)23 CsrProbeForRead(
24 _In_ PVOID Address,
25 _In_ ULONG Length,
26 _In_ ULONG Alignment)
27 {
28 volatile UCHAR *Pointer;
29 UCHAR Data;
30
31 /* Validate length */
32 if (Length == 0) return;
33
34 /* Validate alignment */
35 if ((ULONG_PTR)Address & (Alignment - 1))
36 {
37 /* Raise exception if it doesn't match */
38 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
39 }
40
41 /* Probe first byte */
42 Pointer = Address;
43 Data = *Pointer;
44
45 /* Probe last byte */
46 Pointer = (PUCHAR)Address + Length - 1;
47 Data = *Pointer;
48 (void)Data;
49 }
50
51 /*
52 * @implemented
53 */
54 VOID
55 NTAPI
CsrProbeForWrite(_In_ PVOID Address,_In_ ULONG Length,_In_ ULONG Alignment)56 CsrProbeForWrite(
57 _In_ PVOID Address,
58 _In_ ULONG Length,
59 _In_ ULONG Alignment)
60 {
61 volatile UCHAR *Pointer;
62
63 /* Validate length */
64 if (Length == 0) return;
65
66 /* Validate alignment */
67 if ((ULONG_PTR)Address & (Alignment - 1))
68 {
69 /* Raise exception if it doesn't match */
70 RtlRaiseStatus(STATUS_DATATYPE_MISALIGNMENT);
71 }
72
73 /* Probe first byte */
74 Pointer = Address;
75 *Pointer = *Pointer;
76
77 /* Probe last byte */
78 Pointer = (PUCHAR)Address + Length - 1;
79 *Pointer = *Pointer;
80 }
81
82 /*
83 * @implemented
84 */
85 PCSR_CAPTURE_BUFFER
86 NTAPI
CsrAllocateCaptureBuffer(_In_ ULONG ArgumentCount,_In_ ULONG BufferSize)87 CsrAllocateCaptureBuffer(
88 _In_ ULONG ArgumentCount,
89 _In_ ULONG BufferSize)
90 {
91 PCSR_CAPTURE_BUFFER CaptureBuffer;
92 ULONG OffsetsArraySize;
93 ULONG MaximumSize;
94
95 /* Validate the argument count. Note that on server side, CSRSRV
96 * limits the count to MAXUSHORT; here we are a bit more lenient. */
97 if (ArgumentCount > (MAXLONG / sizeof(ULONG_PTR)))
98 return NULL;
99
100 OffsetsArraySize = ArgumentCount * sizeof(ULONG_PTR);
101
102 /*
103 * Validate the total buffer size.
104 * The total size of the header plus the pointer-offset array and the
105 * provided buffer, together with the alignment padding for each argument,
106 * must be less than MAXLONG aligned to 4-byte boundary.
107 */
108 MaximumSize = (MAXLONG & ~3) - FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray);
109 if (OffsetsArraySize >= MaximumSize)
110 return NULL;
111 MaximumSize -= OffsetsArraySize;
112 if (BufferSize >= MaximumSize)
113 return NULL;
114 MaximumSize -= BufferSize;
115 if ((ArgumentCount * 3) + 3 >= MaximumSize)
116 return NULL;
117
118 /* Add the size of the header and of the pointer-offset array */
119 BufferSize += FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
120 OffsetsArraySize;
121
122 /* Add the size of the alignment padding for each argument */
123 BufferSize += ArgumentCount * 3;
124
125 /* Align it to a 4-byte boundary */
126 BufferSize = (BufferSize + 3) & ~3;
127
128 /* Allocate memory from the port heap */
129 CaptureBuffer = RtlAllocateHeap(CsrPortHeap, HEAP_ZERO_MEMORY, BufferSize);
130 if (CaptureBuffer == NULL) return NULL;
131
132 /* Initialize the header */
133 CaptureBuffer->Size = BufferSize;
134 CaptureBuffer->PointerCount = 0;
135
136 /* Initialize the pointer-offset array */
137 RtlZeroMemory(CaptureBuffer->PointerOffsetsArray, OffsetsArraySize);
138
139 /* Point to the start of the free buffer */
140 CaptureBuffer->BufferEnd = (PVOID)((ULONG_PTR)CaptureBuffer->PointerOffsetsArray +
141 OffsetsArraySize);
142
143 /* Return the address of the buffer */
144 return CaptureBuffer;
145 }
146
147 /*
148 * @implemented
149 */
150 ULONG
151 NTAPI
CsrAllocateMessagePointer(_Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,_In_ ULONG MessageLength,_Out_ PVOID * CapturedData)152 CsrAllocateMessagePointer(
153 _Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,
154 _In_ ULONG MessageLength,
155 _Out_ PVOID* CapturedData)
156 {
157 if (MessageLength == 0)
158 {
159 *CapturedData = NULL;
160 CapturedData = NULL;
161 }
162 else
163 {
164 /* Set the capture data at our current available buffer */
165 *CapturedData = CaptureBuffer->BufferEnd;
166
167 /* Validate the size */
168 if (MessageLength >= MAXLONG) return 0;
169
170 /* Align it to a 4-byte boundary */
171 MessageLength = (MessageLength + 3) & ~3;
172
173 /* Move our available buffer beyond this space */
174 CaptureBuffer->BufferEnd = (PVOID)((ULONG_PTR)CaptureBuffer->BufferEnd + MessageLength);
175 }
176
177 /* Write down this pointer in the array and increase the count */
178 CaptureBuffer->PointerOffsetsArray[CaptureBuffer->PointerCount++] = (ULONG_PTR)CapturedData;
179
180 /* Return the aligned length */
181 return MessageLength;
182 }
183
184 /*
185 * @implemented
186 */
187 VOID
188 NTAPI
CsrCaptureMessageBuffer(_Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,_In_opt_ PVOID MessageBuffer,_In_ ULONG MessageLength,_Out_ PVOID * CapturedData)189 CsrCaptureMessageBuffer(
190 _Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,
191 _In_opt_ PVOID MessageBuffer,
192 _In_ ULONG MessageLength,
193 _Out_ PVOID* CapturedData)
194 {
195 /* Simply allocate a message pointer in the buffer */
196 CsrAllocateMessagePointer(CaptureBuffer, MessageLength, CapturedData);
197
198 /* Check if there was any data */
199 if (!MessageBuffer || !MessageLength) return;
200
201 /* Copy the data into the buffer */
202 RtlMoveMemory(*CapturedData, MessageBuffer, MessageLength);
203 }
204
205 /*
206 * @implemented
207 */
208 VOID
209 NTAPI
CsrFreeCaptureBuffer(_In_ _Frees_ptr_ PCSR_CAPTURE_BUFFER CaptureBuffer)210 CsrFreeCaptureBuffer(
211 _In_ _Frees_ptr_ PCSR_CAPTURE_BUFFER CaptureBuffer)
212 {
213 /* Free it from the heap */
214 RtlFreeHeap(CsrPortHeap, 0, CaptureBuffer);
215 }
216
217 /*
218 * @implemented
219 */
220 VOID
221 NTAPI
CsrCaptureMessageString(_Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,_In_opt_ PCSTR String,_In_ ULONG StringLength,_In_ ULONG MaximumLength,_Out_ PSTRING CapturedString)222 CsrCaptureMessageString(
223 _Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,
224 _In_opt_ PCSTR String,
225 _In_ ULONG StringLength,
226 _In_ ULONG MaximumLength,
227 _Out_ PSTRING CapturedString)
228 {
229 ASSERT(CapturedString != NULL);
230
231 /*
232 * If we don't have a string, initialize an empty one,
233 * otherwise capture the given string.
234 */
235 if (!String)
236 {
237 CapturedString->Length = 0;
238 CapturedString->MaximumLength = (USHORT)MaximumLength;
239
240 /* Allocate a pointer for it */
241 CsrAllocateMessagePointer(CaptureBuffer,
242 MaximumLength,
243 (PVOID*)&CapturedString->Buffer);
244 }
245 else
246 {
247 /* Cut-off the string length if needed */
248 if (StringLength > MaximumLength)
249 StringLength = MaximumLength;
250
251 CapturedString->Length = (USHORT)StringLength;
252
253 /* Allocate a buffer and get its size */
254 CapturedString->MaximumLength =
255 (USHORT)CsrAllocateMessagePointer(CaptureBuffer,
256 MaximumLength,
257 (PVOID*)&CapturedString->Buffer);
258
259 /* If the string has data, copy it into the buffer */
260 if (StringLength)
261 RtlMoveMemory(CapturedString->Buffer, String, StringLength);
262 }
263
264 /* Null-terminate the string if we don't take up the whole space */
265 if (CapturedString->Length < CapturedString->MaximumLength)
266 CapturedString->Buffer[CapturedString->Length] = ANSI_NULL;
267 }
268
269 VOID
270 NTAPI
CsrCaptureMessageUnicodeStringInPlace(_Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,_Inout_ PUNICODE_STRING String)271 CsrCaptureMessageUnicodeStringInPlace(
272 _Inout_ PCSR_CAPTURE_BUFFER CaptureBuffer,
273 _Inout_ PUNICODE_STRING String)
274 {
275 ASSERT(String != NULL);
276
277 /* This is a way to capture the UNICODE string, since (Maximum)Length are also in bytes */
278 CsrCaptureMessageString(CaptureBuffer,
279 (PCSTR)String->Buffer,
280 String->Length,
281 String->MaximumLength,
282 (PSTRING)String);
283
284 /* Null-terminate the string if we don't take up the whole space */
285 if (String->Length + sizeof(WCHAR) <= String->MaximumLength)
286 String->Buffer[String->Length / sizeof(WCHAR)] = UNICODE_NULL;
287 }
288
289 /*
290 * @implemented
291 */
292 NTSTATUS
293 NTAPI
CsrCaptureMessageMultiUnicodeStringsInPlace(_Inout_ PCSR_CAPTURE_BUFFER * CaptureBuffer,_In_ ULONG StringsCount,_In_ PUNICODE_STRING * MessageStrings)294 CsrCaptureMessageMultiUnicodeStringsInPlace(
295 _Inout_ PCSR_CAPTURE_BUFFER* CaptureBuffer,
296 _In_ ULONG StringsCount,
297 _In_ PUNICODE_STRING* MessageStrings)
298 {
299 ULONG Count;
300
301 if (!CaptureBuffer) return STATUS_INVALID_PARAMETER;
302
303 /* Allocate a new capture buffer if we don't have one already */
304 if (!*CaptureBuffer)
305 {
306 /* Compute the required size for the capture buffer */
307 ULONG Size = 0;
308
309 Count = 0;
310 while (Count < StringsCount)
311 {
312 if (MessageStrings[Count])
313 Size += MessageStrings[Count]->MaximumLength;
314
315 ++Count;
316 }
317
318 /* Allocate the capture buffer */
319 *CaptureBuffer = CsrAllocateCaptureBuffer(StringsCount, Size);
320 if (!*CaptureBuffer) return STATUS_NO_MEMORY;
321 }
322
323 /* Now capture each UNICODE string */
324 Count = 0;
325 while (Count < StringsCount)
326 {
327 if (MessageStrings[Count])
328 CsrCaptureMessageUnicodeStringInPlace(*CaptureBuffer, MessageStrings[Count]);
329
330 ++Count;
331 }
332
333 return STATUS_SUCCESS;
334 }
335
336 /*
337 * @implemented
338 */
339 PLARGE_INTEGER
340 NTAPI
CsrCaptureTimeout(_In_ ULONG Milliseconds,_Out_ PLARGE_INTEGER Timeout)341 CsrCaptureTimeout(
342 _In_ ULONG Milliseconds,
343 _Out_ PLARGE_INTEGER Timeout)
344 {
345 /* Validate the time */
346 if (Milliseconds == -1) return NULL;
347
348 /* Convert to relative ticks */
349 Timeout->QuadPart = Milliseconds * -10000LL;
350 return Timeout;
351 }
352
353 /* EOF */
354