kernel
Loading...
Searching...
No Matches
ob.c
Go to the documentation of this file.
1/*++
2
3Module Name:
4
5 ob.c
6
7Purpose:
8
9 This translation unit contains the implementation of the object manager.
10
11Author:
12
13 slep (Matanel) 2025.
14
15Revision History:
16
17--*/
18
19#include "../../includes/ob.h"
20#include "../../includes/mg.h"
21#include "../../includes/md.h"
22#include "../../assert.h"
23#include "../../includes/ps.h"
24#include "../../includes/mt.h"
25
26// Global list of types (for debugging/enumeration)
29volatile void* ObpReaperList = NULL;
30
31
33
35 void
36)
37
38/*++
39
40 Routine description:
41
42 Initializes the Object Manager of the kernel.
43
44 Arguments:
45
46 None.
47
48 Return Values:
49
50 None.
51
52--*/
53
54{
55 ObGlobalLock.locked = false;
57 // Initialize the DPC here, not at the ObpDefer function, as it would overwrite.
60}
61
63 IN char* TypeName,
64 IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
65 OUT POBJECT_TYPE* ReturnedObjectType
66)
67
68/*++
69
70 Routine description:
71
72 Creates an object type for the specified object in the kernel subsystem.
73
74 Arguments:
75
76 [IN] char* TypeName - The name of the object subsystem that will be created for.
77 [IN] POBJECT_TYPE_INITIALIZER ObjectTypeInitializer - The initializer for each object created by ObCreateObject that defines how it should be created & its attributes.
78 [OUT] POBJECT_TYPE* ReturnedObjectType - The returned object type, used to identify this type of object initialization.
79
80 Return Values:
81
82 MTSTATUS Status codes:
83
84 MT_INVALID_PARAM: Invalid parameter, one of them is NULL.
85 MT_NO_MEMORY: No memory is available to create the object type.
86 MT_SUCCESS: Successfully created the object type.
87
88--*/
89
90{
91 if (!TypeName || !ObjectTypeInitializer || !ReturnedObjectType) {
92 return MT_INVALID_PARAM;
93 }
94
95 // Allocate the Type Object itself.
96 POBJECT_TYPE NewType = (POBJECT_TYPE)MmAllocatePoolWithTag(NonPagedPool, sizeof(OBJECT_TYPE), 'epyT'); // Type
97 if (!NewType) return MT_NO_MEMORY;
98
99 // Initialize the Type Object
100 kmemset(NewType, 0, sizeof(OBJECT_TYPE));
101 kstrncpy(NewType->Name, TypeName, 32);
102
103 // Copy the initializer into the object
104 kmemcpy(&NewType->TypeInfo, ObjectTypeInitializer, sizeof(OBJECT_TYPE_INITIALIZER));
105
106 // Link it into the global list
107 IRQL oldIrql;
111
112 // 5. Return the pointer
113 *ReturnedObjectType = NewType;
114 return MT_SUCCESS;
115}
116
119 IN POBJECT_TYPE ObjectType,
120 IN uint32_t ObjectSize,
121 OUT void** ObjectCreated
122 //_In_Opt char* Name - When files arrive, i'll uncomment this.
123)
124
125/*++
126
127 Routine description:
128
129 Creates an object for the specified object type subsystem.
130
131 Arguments:
132
133 [IN] POBJECT_TYPE ObjectType - The object type to create the object for.
134 [IN] uint32_t ObjectBodySize - The size of the object in bytes to create.
135
136 Return Values:
137
138 Pointer to object, or NULL on failure.
139
140--*/
141
142{
143 // 1. Calculate size
144 size_t ActualSize = sizeof(OBJECT_HEADER) + ObjectSize;
145
146 // Allocate memory for the header.
147 POBJECT_HEADER Header = (POBJECT_HEADER)MmAllocatePoolWithTag(ObjectType->TypeInfo.PoolType, ActualSize, 'bObO'); // Ob Object, not bobo, lol.
148 if (!Header) return MT_NO_MEMORY;
149
150 Header->Type = ObjectType;
151 Header->PointerCount = 1; // Start with 1 reference
152 Header->HandleCount = 0;
153
154 // Update stats in the Type object
155 InterlockedIncrementU32((volatile uint32_t*)&ObjectType->TotalNumberOfObjects);
156
157 // Return Body
158 *ObjectCreated = OBJECT_HEADER_TO_OBJECT(Header);
159 return MT_SUCCESS;
160}
161
162bool
164 IN void* Object
165)
166
167/*++
168
169 Routine description:
170
171 References the Object given.
172
173 Arguments:
174
175 [IN] void* Object - The Object to increment reference count for.
176
177 Return Values:
178
179 True if reference succeded, false otherwise (object dying/dead).
180
181--*/
182
183{
184 if (!Object) return false;
186
187 uint64_t expected = __atomic_load_n((volatile uint64_t*)&Header->PointerCount, __ATOMIC_SEQ_CST);
188
189 for (;;) {
190 if (expected == 0) {
191 // object is dying or dead
192 return false;
193 }
194
195 uint64_t desired = expected + 1;
196 // attempt swap: if fail, expected is updated by the function with the new current value
197 if (InterlockedCompareExchangeU64_bool((volatile uint64_t*)&Header->PointerCount, desired, &expected)) {
198 return true;
199 }
200 // loop with updated expected
201 }
202}
203
206 IN void* Object,
207 IN POBJECT_TYPE DesiredType
208)
209
210/*++
211
212 Routine description:
213
214 References the Object given by its pointer.
215
216 Arguments:
217
218 [IN] void* Object - The Object to increment reference count for.
219 [IN] POBJECT_TYPE DesiredType - The type we EXPECT the Object to be (PsProcessType, PsThreadType, etc..)
220
221 Return Values:
222
223 MT_SUCCESS if reference succeeded.
224 MT_TYPE_MISMATCH if DesiredType isn't the Object's actual OBJECT_TYPE.
225 MT_INVALID_PARAM if Object is NULL.
226 MT_OBJECT_DELETED if Object is deleted / ongoing deletion.
227
228 MT_BETTER_THAN_WINDOWS if (true)
229
230--*/
231
232{
233 if (!Object) return MT_INVALID_PARAM;
234
236
237 // If the caller expects a process but gets a thread or a file, we say no no bye bye.
238 if (Header->Type != DesiredType) {
239 return MT_TYPE_MISMATCH;
240 }
241
242 // We reference it.
243 if (ObReferenceObject(Object)) {
244 return MT_SUCCESS;
245 }
246
247 // Object is RIP, we return.
248 return MT_OBJECT_DELETED;
249}
250
253 IN void* Object,
254 IN POBJECT_TYPE ObjectType,
255 IN ACCESS_MASK DesiredAccess,
256 OUT PHANDLE Handle
257)
258
259{
260 // Assume failure.
261 *Handle = 0;
262
263 // Reference the object.
264 MTSTATUS Status = ObReferenceObjectByPointer(Object, ObjectType);
265 if (MT_FAILURE(Status)) return Status;
266
267 // Create handle.
268 Status = ObCreateHandleForObject(Object, DesiredAccess, Handle);
269
270 // Drop the temporary reference in all cases.
271 ObDereferenceObject(Object);
272
273 return Status;
274}
275
278 IN HANDLE Handle,
279 IN uint32_t DesiredAccess,
280 IN POBJECT_TYPE DesiredType,
281 OUT void** Object,
282 _Out_Opt PHANDLE_TABLE_ENTRY HandleInformation
283)
284
285/*++
286
287 Routine description:
288
289 References the Object given by its given handle.
290
291 Arguments:
292
293 [IN] HANDLE Handle - The handle to reference the object for.
294 [IN] uint32_t DesiredAccess - The access rights requested for the object.
295 [IN] POBJECT_TYPE DesiredType - The type we EXPECT the Object to be (PsProcessType, PsThreadType, etc..)
296 [OUT] void** Object - The pointer to the object expected.
297 [OUT OPTIONAL] PHANDLE_TABLE_ENTRY HandleInformation - Information about the handle given if MT_SUCCESS is returned.
298
299 Return Values:
300
301 MT_SUCCESS if reference succeeded.
302 MT_INVALID_HANDLE if the HANDLE is simply invalid (doesn't exist, or table doesnt exist)
303 MT_TYPE_MISMATCH if DesiredType isn't the Object's actual OBJECT_TYPE.
304 MT_INVALID_PARAM if Object is NULL.
305 MT_OBJECT_DELETED if Object is deleted / ongoing deletion.
306 MT_ACCESS_DENIED if the desired access does not meet the access rights of the Object.
307
308 MT_BETTER_THAN_WINDOWS if (true)
309
310--*/
311
312{
313 // Set initially to NULL. (to overwrite stack default if uninitialized)
314 *Object = NULL;
316
317 // Check for special handles
318 if (Handle < 0) {
319 if (Handle == MtCurrentProcess()) {
320 if (DesiredType == PsProcessType) {
321 PEPROCESS CurrentProcess = PsGetCurrentProcess();
322
323 // Check if caller wants handle information
324 if (HandleInformation) {
325 HandleInformation->GrantedAccess = MT_PROCESS_ALL_ACCESS;
326 HandleInformation->Object = CurrentProcess;
327 }
328
329 // Reference ourselves
330 ObReferenceObject(CurrentProcess);
331
332 // Return pointer.
333 *Object = CurrentProcess;
334 Status = MT_SUCCESS;
335 }
336 else {
337 Status = MT_TYPE_MISMATCH;
338 }
339 }
340 else if (Handle == MtCurrentThread()) {
341 if (DesiredType == PsThreadType) {
342 PETHREAD CurrentThread = PsGetCurrentThread();
343
344 // Check if caller wants handle information
345 if (HandleInformation) {
346 HandleInformation->GrantedAccess = MT_THREAD_ALL_ACCESS;
347 HandleInformation->Object = CurrentThread;
348 }
349
350 // Reference ourselves
351 ObReferenceObject(CurrentThread);
352
353 // Return pointer.
354 *Object = CurrentThread;
355 Status = MT_SUCCESS;
356 }
357 else {
358 Status = MT_TYPE_MISMATCH;
359 }
360 }
361
362 if (MT_FAILURE(Status)) {
363 return Status;
364 }
365 }
366
367
368 // Get the handle table from current process (requesting process)
369 PEPROCESS Process = PsGetCurrentProcess();
370 if (!Process || !Process->ObjectTable) return MT_INVALID_HANDLE;
371
372 // Lookup in the handle table.
373 PHANDLE_TABLE_ENTRY OutHandleEntry = NULL;
374 void* RetrievedObject = HtGetObject(Process->ObjectTable, Handle, &OutHandleEntry);
375 if (!RetrievedObject) return MT_INVALID_HANDLE;
376
377 // Get the header.
378 POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(RetrievedObject);
379
380 // Lets check if the type matches
381 if (DesiredType && Header->Type != DesiredType) {
382 // Invalid type.
383 return MT_TYPE_MISMATCH;
384 }
385
386 // Remove the invalid access masks.
387 DesiredAccess = DesiredAccess & DesiredType->TypeInfo.ValidAccessRights;
388
389 // Check access.
390 if ((OutHandleEntry->GrantedAccess & DesiredAccess) != DesiredAccess) {
391 // Access is invalid.
392 return MT_ACCESS_DENIED;
393 }
394
395 // Wow!! It is all good!!, reference it.
396 ObReferenceObject(RetrievedObject);
397 *Object = RetrievedObject;
398 if (HandleInformation) *HandleInformation = *OutHandleEntry;
399 return MT_SUCCESS;
400}
401
404 IN void* Object,
405 IN ACCESS_MASK DesiredAccess,
406 OUT PHANDLE ReturnedHandle
407)
408
409/*++
410
411 Routine description:
412
413 Creates a handle in the current process's handle table for the specified Object.
414
415 Arguments:
416
417 [IN] void* Object - The object to create the handle for.
418 [IN] ACCESS_MASK DesiredAccess - The maximum access the handle should have.
419 [OUT] PHANDLE ReturnedHandle - The returned handle for the object if success.
420
421 Return Values:
422
423 MTSTATUS Status Codes:
424
425 MT_SUCCESS - Successful.
426 MT_INVALID_STATE - No handle table for current process.
427 MT_INVALID_CHECK - HtCreateHandle returned MT_INVALID_HANDLE.
428--*/
429
430{
431 // Acquire the object table.
433 if (!ObjectTable) return MT_INVALID_ADDRESS;
434
435 // Use the extended function.
436 return ObCreateHandleForObjectEx(Object, DesiredAccess, ReturnedHandle, ObjectTable);
437}
438
441 IN void* Object,
442 IN ACCESS_MASK DesiredAccess,
443 OUT PHANDLE ReturnedHandle,
444 IN PHANDLE_TABLE ObjectTable
445)
446
447/*++
448
449 Routine description:
450
451 Creates a handle in the specified handle table for the specified Object.
452 This also references the object since a handle is created for it.
453
454 Arguments:
455
456 [IN] void* Object - The object to create the handle for.
457 [IN] ACCESS_MASK DesiredAccess - The maximum access the handle should have.
458 [OUT] PHANDLE ReturnedHandle - The returned handle for the object if success.
459 [IN] PHANDLE_TABLE ObjectTable - The handle table to insert the newly created handle in.
460
461 Return Values:
462
463 MTSTATUS Status Codes:
464
465 MT_SUCCESS - Successful.
466 MT_INVALID_STATE - No handle table for current process.
467 MT_INVALID_CHECK - HtCreateHandle returned MT_INVALID_HANDLE.
468--*/
469
470{
471 if (!ObjectTable || !Object) return MT_INVALID_ADDRESS;
473
474 // Create the handle.
475 HANDLE Handle = HtCreateHandle(ObjectTable, Object, DesiredAccess);
476 if (Handle == MT_INVALID_HANDLE) return MT_INVALID_CHECK;
477
478 // Increment handle count.
479 Header->HandleCount++;
480 Header->Type->TotalNumberOfHandles++;
481
482 // Reference the object.
483 ObReferenceObject(Object);
484
485 // Return success.
486 *ReturnedHandle = Handle;
487 return MT_SUCCESS;
488}
489
490static
491void
492ObpDeferObjectDeletion(
493 IN POBJECT_HEADER Header
494)
495
496/*++
497
498 Routine description:
499
500 Defers object deletion to a DPC, to ensure no use after free.
501
502 Arguments:
503
504 [IN] POBJECT_HEADER Header - The object header to defer deletion for.
505
506 Return Values:
507
508 None.
509
510--*/
511
512{
513 volatile void* Entry;
514 do {
515 // Get the current entry.
516 Entry = ObpReaperList;
517
518 // Link our object to the linked list.
519 Header->NextToFree = Entry;
520 // Update the list
521 } while (InterlockedCompareExchangePointer(&ObpReaperList, Header, (void*)Entry) != Entry);
522
523 if (!Entry) {
524 // Looks like a DPC hasn't been queued yet, lets do so!
525 MeInsertQueueDpc(&ObpReaperDpc, NULL, NULL);
526 }
527}
528
530 IN POBJECT_HEADER Header
531)
532
533{
534 // Pointers and handles must be 0.
535 assert(Header->HandleCount == 0 && Header->PointerCount == 0);
536 // Get the type initializer for the object.
537 POBJECT_TYPE Type = Header->Type;
538
539#ifdef DEBUG
540 // First call debug callback if exists
541 if (Type->TypeInfo.DumpProcedure) Type->TypeInfo.DumpProcedure(OBJECT_HEADER_TO_OBJECT(Header));
542#endif
543
544 // Call Delete Callback if it exists
545 if (Type->TypeInfo.DeleteProcedure) Type->TypeInfo.DeleteProcedure(OBJECT_HEADER_TO_OBJECT(Header));
546
547 // Update Stats
548 InterlockedDecrementU32((volatile uint32_t*)&Type->TotalNumberOfObjects);
549 // Free Memory
550 gop_printf(COLOR_RED, "Freeing the header\n");
551 MmFreePool(Header);
552}
553
555 IN void* Object
556)
557
558/*++
559
560 Routine description:
561
562 Dereferences the Object given.
563
564 Arguments:
565
566 [IN] void* Object - The Object to decrement reference count for.
567
568 Return Values:
569
570 None.
571
572 Notes:
573
574 On reference count 0, object is deleted using type initializer routine.
575
576--*/
577
578{
579 if (!Object) return;
581
582 uint64_t NewCount = InterlockedDecrementU64((volatile uint64_t*)&Header->PointerCount);
583
584 if (NewCount == 0) {
585 // NO HANDLES Must be open if we delete the object, its a use after free.
586 assert(Header->HandleCount == 0);
587 // Free Memory (defer it)
588 //ObpDeferObjectDeletion(Header);
593 ObDeleteObject(Header);
594 }
595}
#define _Out_Opt
Definition annotations.h:11
#define IN
Definition annotations.h:8
#define OUT
Definition annotations.h:9
#define assert(...)
Definition assert.h:57
FORCEINLINE uint32_t InterlockedIncrementU32(volatile uint32_t *target)
Definition atomic.h:121
FORCEINLINE void * InterlockedCompareExchangePointer(volatile void *volatile *target, void *value, void *comparand)
Definition atomic.h:177
FORCEINLINE uint32_t InterlockedDecrementU32(volatile uint32_t *target)
Definition atomic.h:122
FORCEINLINE uint64_t InterlockedDecrementU64(volatile uint64_t *target)
Definition atomic.h:128
FORCEINLINE bool InterlockedCompareExchangeU64_bool(volatile uint64_t *target, uint64_t value, uint64_t *expected)
Definition atomic.h:92
uint32_t ACCESS_MASK
Definition core.h:59
int32_t * PHANDLE
Definition core.h:58
enum _IRQL IRQL
int32_t HANDLE
Definition core.h:58
EPROCESS * PEPROCESS
Definition core.h:52
ETHREAD * PETHREAD
Definition core.h:44
struct _DOUBLY_LINKED_LIST DOUBLY_LINKED_LIST
bool MeInsertQueueDpc(IN PDPC Dpc, IN void *SystemArgument1, IN void *SystemArgument2)
Definition dpc.c:48
volatile void * ObpReaperList
Definition ob.c:29
void MeInitializeDpc(IN PDPC DpcAllocated, IN PDEFERRED_ROUTINE DeferredRoutine, IN void *DeferredContext, IN DPC_PRIORITY DeferredPriority)
Definition dpc.c:385
void ReapOb(DPC *dpc, void *DeferredContext, void *SystemArgument1, void *SystemArgument2)
Definition dpc.c:19
void gop_printf(uint32_t color, const char *fmt,...)
Definition gop.c:633
char * kstrncpy(char *dst, const char *src, size_t n)
Definition gop.c:365
HANDLE HtCreateHandle(PHANDLE_TABLE Table, void *Object, uint32_t Access)
Definition handle.c:277
void * HtGetObject(IN PHANDLE_TABLE Table, IN HANDLE Handle, _Out_Opt PHANDLE_TABLE_ENTRY *OutEntry)
Definition handle.c:397
struct _HANDLE_TABLE_ENTRY * PHANDLE_TABLE_ENTRY
struct _HANDLE_TABLE * PHANDLE_TABLE
@ MEDIUM_PRIORITY
Definition me.h:60
struct _DPC DPC
#define COLOR_RED
Colors definitions for easier access.
Definition mg.h:30
@ NonPagedPool
Definition mm.h:355
FORCEINLINE void * kmemcpy(void *dest, const void *src, size_t len)
Definition mm.h:669
FORCEINLINE void * kmemset(void *dest, int64_t val, uint64_t len)
Definition mm.h:655
FORCEINLINE void InitializeListHead(PDOUBLY_LINKED_LIST Head)
Definition ms.h:223
FORCEINLINE void InsertTailList(PDOUBLY_LINKED_LIST Head, PDOUBLY_LINKED_LIST Entry)
Definition ms.h:236
struct _SPINLOCK SPINLOCK
#define MtCurrentThread()
Definition mt.h:29
#define MtCurrentProcess()
Definition mt.h:28
#define MT_NO_MEMORY
Definition mtstatus.h:42
#define MT_TYPE_MISMATCH
Definition mtstatus.h:34
#define MT_SUCCESS
Definition mtstatus.h:22
#define MT_ACCESS_DENIED
Definition mtstatus.h:26
#define MT_INVALID_ADDRESS
Definition mtstatus.h:46
#define MT_FAILURE(Status)
Definition mtstatus.h:16
#define MT_INVALID_PARAM
Definition mtstatus.h:24
#define MT_OBJECT_DELETED
Definition mtstatus.h:35
int32_t MTSTATUS
Definition mtstatus.h:12
#define MT_INVALID_HANDLE
Definition mtstatus.h:36
#define MT_INVALID_CHECK
Definition mtstatus.h:33
MTSTATUS ObCreateHandleForObject(IN void *Object, IN ACCESS_MASK DesiredAccess, OUT PHANDLE ReturnedHandle)
Definition ob.c:403
void ObInitialize(void)
Definition ob.c:34
MTSTATUS ObReferenceObjectByHandle(IN HANDLE Handle, IN uint32_t DesiredAccess, IN POBJECT_TYPE DesiredType, OUT void **Object, _Out_Opt PHANDLE_TABLE_ENTRY HandleInformation)
Definition ob.c:277
MTSTATUS ObReferenceObjectByPointer(IN void *Object, IN POBJECT_TYPE DesiredType)
Definition ob.c:205
MTSTATUS ObCreateHandleForObjectEx(IN void *Object, IN ACCESS_MASK DesiredAccess, OUT PHANDLE ReturnedHandle, IN PHANDLE_TABLE ObjectTable)
Definition ob.c:440
MTSTATUS ObCreateObjectType(IN char *TypeName, IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, OUT POBJECT_TYPE *ReturnedObjectType)
Definition ob.c:62
void ObDereferenceObject(IN void *Object)
Definition ob.c:554
DPC ObpReaperDpc
Definition ob.c:32
bool ObReferenceObject(IN void *Object)
Definition ob.c:163
SPINLOCK ObGlobalLock
Definition ob.c:28
void ObDeleteObject(IN POBJECT_HEADER Header)
Definition ob.c:529
MTSTATUS ObCreateObject(IN POBJECT_TYPE ObjectType, IN uint32_t ObjectSize, OUT void **ObjectCreated)
Definition ob.c:118
MTSTATUS ObOpenObjectByPointer(IN void *Object, IN POBJECT_TYPE ObjectType, IN ACCESS_MASK DesiredAccess, OUT PHANDLE Handle)
Definition ob.c:252
DOUBLY_LINKED_LIST ObTypeDirectoryList
Definition ob.c:27
struct _OBJECT_TYPE * POBJECT_TYPE
POBJECT_TYPE Type
Definition ob.h:5
struct _OBJECT_TYPE_INITIALIZER * POBJECT_TYPE_INITIALIZER
#define OBJECT_HEADER_TO_OBJECT(h)
Definition ob.h:71
struct _OBJECT_HEADER * POBJECT_HEADER
Definition ob.h:64
struct _OBJECT_TYPE OBJECT_TYPE
struct _OBJECT_TYPE_INITIALIZER OBJECT_TYPE_INITIALIZER
#define OBJECT_TO_OBJECT_HEADER(o)
Definition ob.h:68
void MmFreePool(IN void *buf)
Definition pool.c:632
void * MmAllocatePoolWithTag(IN enum _POOL_TYPE PoolType, IN size_t NumberOfBytes, IN uint32_t Tag)
Definition pool.c:443
FORCEINLINE PEPROCESS PsGetCurrentProcess(void)
Definition ps.h:300
#define MT_THREAD_ALL_ACCESS
Definition ps.h:72
#define MT_PROCESS_ALL_ACCESS
Definition ps.h:89
POBJECT_TYPE PsThreadType
Definition psmgr.c:31
POBJECT_TYPE PsProcessType
Definition psmgr.c:30
void MsAcquireSpinlock(IN PSPINLOCK lock, IN PIRQL OldIrql)
Definition spinlock.c:13
void MsReleaseSpinlock(IN PSPINLOCK lock, IN IRQL OldIrql)
Definition spinlock.c:45
PHANDLE_TABLE ObjectTable
Definition ps.h:171
uint32_t GrantedAccess
Definition ht.h:33
DOUBLY_LINKED_LIST TypeList
Definition ob.h:48
char Name[32]
Definition ob.h:49
OBJECT_TYPE_INITIALIZER TypeInfo
Definition ob.h:52
PETHREAD PsGetCurrentThread(void)
Definition thread.c:279