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 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 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 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 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 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 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 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 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 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 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