- Fix multiple bugs in RtlWalkFrameChain and secure it against any possibility of...
[reactos.git] / reactos / ntoskrnl / rtl / libsupp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/rtl/libsupp.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 extern ULONG NtGlobalFlag;
17
18 typedef struct _RTL_RANGE_ENTRY
19 {
20 LIST_ENTRY Entry;
21 RTL_RANGE Range;
22 } RTL_RANGE_ENTRY, *PRTL_RANGE_ENTRY;
23
24 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList;
25
26 /* FUNCTIONS *****************************************************************/
27
28 VOID
29 NTAPI
30 RtlInitializeRangeListPackage(VOID)
31 {
32 /* Setup the lookaside list for allocations (not used yet) */
33 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList,
34 NULL,
35 NULL,
36 POOL_COLD_ALLOCATION,
37 sizeof(RTL_RANGE_ENTRY),
38 TAG('R', 'R', 'l', 'e'),
39 16);
40 }
41
42 BOOLEAN
43 NTAPI
44 RtlpCheckForActiveDebugger(BOOLEAN Type)
45 {
46 /* This check is meaningless in kernel-mode */
47 return Type;
48 }
49
50 BOOLEAN
51 NTAPI
52 RtlpSetInDbgPrint(IN BOOLEAN NewValue)
53 {
54 /* This check is meaningless in kernel-mode */
55 return FALSE;
56 }
57
58 KPROCESSOR_MODE
59 STDCALL
60 RtlpGetMode()
61 {
62 return KernelMode;
63 }
64
65 PVOID
66 STDCALL
67 RtlpAllocateMemory(ULONG Bytes,
68 ULONG Tag)
69 {
70 return ExAllocatePoolWithTag(PagedPool,
71 (SIZE_T)Bytes,
72 Tag);
73 }
74
75
76 VOID
77 STDCALL
78 RtlpFreeMemory(PVOID Mem,
79 ULONG Tag)
80 {
81 ExFreePoolWithTag(Mem,
82 Tag);
83 }
84
85 /*
86 * @implemented
87 */
88 VOID STDCALL
89 RtlAcquirePebLock(VOID)
90 {
91
92 }
93
94 /*
95 * @implemented
96 */
97 VOID STDCALL
98 RtlReleasePebLock(VOID)
99 {
100
101 }
102
103 NTSTATUS
104 STDCALL
105 LdrShutdownThread(VOID)
106 {
107 return STATUS_SUCCESS;
108 }
109
110
111 PPEB
112 STDCALL
113 RtlpCurrentPeb(VOID)
114 {
115 return ((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->Peb;
116 }
117
118 NTSTATUS
119 STDCALL
120 RtlDeleteHeapLock(
121 PRTL_CRITICAL_SECTION CriticalSection)
122 {
123 KEBUGCHECK(0);
124 return STATUS_SUCCESS;
125 }
126
127 NTSTATUS
128 STDCALL
129 RtlEnterHeapLock(
130 PRTL_CRITICAL_SECTION CriticalSection)
131 {
132 KEBUGCHECK(0);
133 return STATUS_SUCCESS;
134 }
135
136 NTSTATUS
137 STDCALL
138 RtlInitializeHeapLock(
139 PRTL_CRITICAL_SECTION CriticalSection)
140 {
141 KEBUGCHECK(0);
142 return STATUS_SUCCESS;
143 }
144
145 NTSTATUS
146 STDCALL
147 RtlLeaveHeapLock(
148 PRTL_CRITICAL_SECTION CriticalSection)
149 {
150 KEBUGCHECK(0);
151 return STATUS_SUCCESS;
152 }
153
154 #ifdef DBG
155 VOID FASTCALL
156 CHECK_PAGED_CODE_RTL(char *file, int line)
157 {
158 if(KeGetCurrentIrql() > APC_LEVEL)
159 {
160 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%d)\n", file, line, KeGetCurrentIrql());
161 KEBUGCHECK(0);
162 }
163 }
164 #endif
165
166 VOID
167 NTAPI
168 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
169 IN PCONTEXT ContextRecord,
170 IN PVOID ContextData,
171 IN ULONG Size)
172 {
173 /* Check the global flag */
174 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
175 {
176 /* FIXME: Log this exception */
177 }
178 }
179
180 BOOLEAN
181 NTAPI
182 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
183 IN ULONG_PTR RegistrationFrameEnd,
184 IN OUT PULONG_PTR StackLow,
185 IN OUT PULONG_PTR StackHigh)
186 {
187 PKPRCB Prcb;
188 ULONG_PTR DpcStack;
189
190 /* Check if we are at DISPATCH or higher */
191 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
192 {
193 /* Get the PRCB and DPC Stack */
194 Prcb = KeGetCurrentPrcb();
195 DpcStack = (ULONG_PTR)Prcb->DpcStack;
196
197 /* Check if we are in a DPC and the stack matches */
198 if ((Prcb->DpcRoutineActive) &&
199 (RegistrationFrameEnd <= DpcStack) &&
200 ((ULONG_PTR)RegistrationFrame >= DpcStack - KERNEL_STACK_SIZE))
201 {
202 /* Update the limits to the DPC Stack's */
203 *StackHigh = DpcStack;
204 *StackLow = DpcStack - KERNEL_STACK_SIZE;
205 return TRUE;
206 }
207 }
208
209 /* Not in DPC stack */
210 return FALSE;
211 }
212
213 BOOLEAN
214 NTAPI
215 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
216 IN ULONG_PTR *StackBegin,
217 IN ULONG_PTR *StackEnd)
218 {
219 PKTHREAD Thread = KeGetCurrentThread();
220
221 /* Don't even try at ISR level or later */
222 if (KeGetCurrentIrql() > DISPATCH_LEVEL) return FALSE;
223
224 /* Start with defaults */
225 *StackBegin = Thread->StackLimit;
226 *StackEnd = (ULONG_PTR)Thread->StackBase;
227
228 /* Check if EBP is inside the stack */
229 if ((*StackBegin <= Ebp) && (Ebp <= *StackEnd))
230 {
231 /* Then make the stack start at EBP */
232 *StackBegin = Ebp;
233 }
234 else
235 {
236 /* Now we're going to assume we're on the DPC stack */
237 *StackEnd = (ULONG_PTR)(KeGetPcr()->Prcb->DpcStack);
238 *StackBegin = *StackEnd - KERNEL_STACK_SIZE;
239
240 /* Check if we seem to be on the DPC stack */
241 if ((*StackEnd) && (*StackBegin < Ebp) && (Ebp <= *StackEnd))
242 {
243 /* We're on the DPC stack */
244 *StackBegin = Ebp;
245 }
246 else
247 {
248 /* We're somewhere else entirely... use EBP for safety */
249 *StackBegin = Ebp;
250 *StackEnd = (ULONG_PTR)PAGE_ALIGN(*StackBegin);
251 }
252 }
253
254 /* Return success */
255 return TRUE;
256 }
257
258 /* RTL Atom Tables ************************************************************/
259
260 NTSTATUS
261 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
262 {
263 ExInitializeFastMutex(&AtomTable->FastMutex);
264
265 return STATUS_SUCCESS;
266 }
267
268
269 VOID
270 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
271 {
272 }
273
274
275 BOOLEAN
276 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
277 {
278 ExAcquireFastMutex(&AtomTable->FastMutex);
279 return TRUE;
280 }
281
282 VOID
283 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
284 {
285 ExReleaseFastMutex(&AtomTable->FastMutex);
286 }
287
288 BOOLEAN
289 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
290 {
291 AtomTable->ExHandleTable = ExCreateHandleTable(NULL);
292 return (AtomTable->ExHandleTable != NULL);
293 }
294
295 VOID
296 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
297 {
298 if (AtomTable->ExHandleTable)
299 {
300 ExSweepHandleTable(AtomTable->ExHandleTable,
301 NULL,
302 NULL);
303 ExDestroyHandleTable(AtomTable->ExHandleTable, NULL);
304 AtomTable->ExHandleTable = NULL;
305 }
306 }
307
308 PRTL_ATOM_TABLE
309 RtlpAllocAtomTable(ULONG Size)
310 {
311 PRTL_ATOM_TABLE Table = ExAllocatePool(NonPagedPool,
312 Size);
313 if (Table != NULL)
314 {
315 RtlZeroMemory(Table,
316 Size);
317 }
318
319 return Table;
320 }
321
322 VOID
323 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
324 {
325 ExFreePool(AtomTable);
326 }
327
328 PRTL_ATOM_TABLE_ENTRY
329 RtlpAllocAtomTableEntry(ULONG Size)
330 {
331 PRTL_ATOM_TABLE_ENTRY Entry = ExAllocatePool(NonPagedPool,
332 Size);
333 if (Entry != NULL)
334 {
335 RtlZeroMemory(Entry,
336 Size);
337 }
338
339 return Entry;
340 }
341
342 VOID
343 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
344 {
345 ExFreePool(Entry);
346 }
347
348 VOID
349 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
350 {
351 ExDestroyHandle(AtomTable->ExHandleTable,
352 (HANDLE)((ULONG_PTR)Entry->HandleIndex << 2),
353 NULL);
354 }
355
356 BOOLEAN
357 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
358 {
359 HANDLE_TABLE_ENTRY ExEntry;
360 HANDLE Handle;
361 USHORT HandleIndex;
362
363 ExEntry.Object = Entry;
364 ExEntry.GrantedAccess = 0x1; /* FIXME - valid handle */
365
366 Handle = ExCreateHandle(AtomTable->ExHandleTable,
367 &ExEntry);
368 if (Handle != NULL)
369 {
370 HandleIndex = (USHORT)((ULONG_PTR)Handle >> 2);
371 /* FIXME - Handle Indexes >= 0xC000 ?! */
372 if ((ULONG_PTR)HandleIndex >> 2 < 0xC000)
373 {
374 Entry->HandleIndex = HandleIndex;
375 Entry->Atom = 0xC000 + HandleIndex;
376
377 return TRUE;
378 }
379 else
380 ExDestroyHandle(AtomTable->ExHandleTable,
381 Handle,
382 NULL);
383 }
384
385 return FALSE;
386 }
387
388 PRTL_ATOM_TABLE_ENTRY
389 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
390 {
391 PHANDLE_TABLE_ENTRY ExEntry;
392 PRTL_ATOM_TABLE_ENTRY Entry = NULL;
393
394 /* NOTE: There's no need to explicitly enter a critical region because it's
395 guaranteed that we're in a critical region right now (as we hold
396 the atom table lock) */
397
398 ExEntry = ExMapHandleToPointer(AtomTable->ExHandleTable,
399 (HANDLE)((ULONG_PTR)Index << 2));
400 if (ExEntry != NULL)
401 {
402 Entry = ExEntry->Object;
403
404 ExUnlockHandleTableEntry(AtomTable->ExHandleTable,
405 ExEntry);
406 }
407
408 return Entry;
409 }
410
411 /* FIXME - RtlpCreateUnicodeString is obsolete and should be removed ASAP! */
412 BOOLEAN FASTCALL
413 RtlpCreateUnicodeString(
414 IN OUT PUNICODE_STRING UniDest,
415 IN PCWSTR Source,
416 IN POOL_TYPE PoolType)
417 {
418 ULONG Length;
419
420 Length = (wcslen (Source) + 1) * sizeof(WCHAR);
421 UniDest->Buffer = ExAllocatePoolWithTag(PoolType, Length, TAG('U', 'S', 'T', 'R'));
422 if (UniDest->Buffer == NULL)
423 return FALSE;
424
425 RtlCopyMemory (UniDest->Buffer,
426 Source,
427 Length);
428
429 UniDest->MaximumLength = (USHORT)Length;
430 UniDest->Length = (USHORT)Length - sizeof (WCHAR);
431
432 return TRUE;
433 }
434
435 /*
436 * Ldr Resource support code
437 */
438
439 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
440 LPCWSTR name, void *root,
441 int want_dir );
442 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
443 USHORT id, void *root, int want_dir );
444 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
445 void *root, int want_dir );
446
447 /**********************************************************************
448 * find_entry
449 *
450 * Find a resource entry
451 */
452 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
453 ULONG level, void **ret, int want_dir )
454 {
455 ULONG size;
456 void *root;
457 IMAGE_RESOURCE_DIRECTORY *resdirptr;
458
459 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
460 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
461 resdirptr = root;
462
463 if (!level--) goto done;
464 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
465 return STATUS_RESOURCE_TYPE_NOT_FOUND;
466 if (!level--) return STATUS_SUCCESS;
467
468 resdirptr = *ret;
469 if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
470 return STATUS_RESOURCE_NAME_NOT_FOUND;
471 if (!level--) return STATUS_SUCCESS;
472 if (level) return STATUS_INVALID_PARAMETER; /* level > 3 */
473
474 resdirptr = *ret;
475
476 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
477
478 return STATUS_RESOURCE_DATA_NOT_FOUND;
479
480 done:
481 *ret = resdirptr;
482 return STATUS_SUCCESS;
483 }
484
485
486 /* EOF */