xref: /reactos/subsystems/csr/csrlib/capture.c (revision 8cd01eaf)
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