xref: /reactos/ntoskrnl/ex/mutant.c (revision d0d86ab5)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel
4  * FILE:            ntoskrnl/ex/mutant.c
5  * PURPOSE:         Executive Management of Mutants
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  *                  Thomas Weidenmueller
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* DATA **********************************************************************/
17 
18 POBJECT_TYPE ExMutantObjectType = NULL;
19 
20 GENERIC_MAPPING ExpMutantMapping =
21 {
22     STANDARD_RIGHTS_READ | MUTANT_QUERY_STATE,
23     STANDARD_RIGHTS_WRITE,
24     STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
25     MUTANT_ALL_ACCESS
26 };
27 
28 static const INFORMATION_CLASS_INFO ExMutantInfoClass[] =
29 {
30      /* MutantBasicInformation */
31     IQS_SAME(MUTANT_BASIC_INFORMATION, ULONG, ICIF_QUERY),
32 };
33 
34 /* FUNCTIONS *****************************************************************/
35 
36 VOID
37 NTAPI
ExpDeleteMutant(PVOID ObjectBody)38 ExpDeleteMutant(PVOID ObjectBody)
39 {
40     DPRINT("ExpDeleteMutant(ObjectBody 0x%p)\n", ObjectBody);
41 
42     /* Make sure to release the Mutant */
43     KeReleaseMutant((PKMUTANT)ObjectBody,
44                     MUTANT_INCREMENT,
45                     TRUE,
46                     FALSE);
47 }
48 
49 CODE_SEG("INIT")
50 BOOLEAN
51 NTAPI
ExpInitializeMutantImplementation(VOID)52 ExpInitializeMutantImplementation(VOID)
53 {
54     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
55     UNICODE_STRING Name;
56     NTSTATUS Status;
57     DPRINT("Creating Mutant Object Type\n");
58 
59     /* Create the Event Pair Object Type */
60     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
61     RtlInitUnicodeString(&Name, L"Mutant");
62     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
63     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KMUTANT);
64     ObjectTypeInitializer.GenericMapping = ExpMutantMapping;
65     ObjectTypeInitializer.PoolType = NonPagedPool;
66     ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant;
67     ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS;
68     ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
69     Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExMutantObjectType);
70     if (!NT_SUCCESS(Status)) return FALSE;
71     return TRUE;
72 }
73 
74 /*
75  * @implemented
76  */
77 NTSTATUS
78 NTAPI
NtCreateMutant(OUT PHANDLE MutantHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN BOOLEAN InitialOwner)79 NtCreateMutant(OUT PHANDLE MutantHandle,
80                IN ACCESS_MASK DesiredAccess,
81                IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
82                IN BOOLEAN InitialOwner)
83 {
84     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
85     HANDLE hMutant;
86     PKMUTANT Mutant;
87     NTSTATUS Status;
88     PAGED_CODE();
89     DPRINT("NtCreateMutant(0x%p, 0x%x, 0x%p)\n",
90             MutantHandle, DesiredAccess, ObjectAttributes);
91 
92     /* Check if we were called from user-mode */
93     if (PreviousMode != KernelMode)
94     {
95         /* Enter SEH Block */
96         _SEH2_TRY
97         {
98             /* Check handle pointer */
99             ProbeForWriteHandle(MutantHandle);
100         }
101         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
102         {
103             /* Return the exception code */
104             _SEH2_YIELD(return _SEH2_GetExceptionCode());
105         }
106         _SEH2_END;
107     }
108 
109     /* Create the Mutant Object*/
110     Status = ObCreateObject(PreviousMode,
111                             ExMutantObjectType,
112                             ObjectAttributes,
113                             PreviousMode,
114                             NULL,
115                             sizeof(KMUTANT),
116                             0,
117                             0,
118                             (PVOID*)&Mutant);
119 
120     /* Check for success */
121     if(NT_SUCCESS(Status))
122     {
123         /* Initialize the Kernel Mutant */
124         DPRINT("Initializing the Mutant\n");
125         KeInitializeMutant(Mutant, InitialOwner);
126 
127         /* Insert the Object */
128         Status = ObInsertObject((PVOID)Mutant,
129                                 NULL,
130                                 DesiredAccess,
131                                 0,
132                                 NULL,
133                                 &hMutant);
134 
135         /* Check for success */
136         if (NT_SUCCESS(Status))
137         {
138             /* Enter SEH for return */
139             _SEH2_TRY
140             {
141                 /* Return the handle to the caller */
142                 *MutantHandle = hMutant;
143             }
144             _SEH2_EXCEPT(ExSystemExceptionFilter())
145             {
146                 /* Get the exception code */
147                 Status = _SEH2_GetExceptionCode();
148             }
149             _SEH2_END;
150         }
151     }
152 
153     /* Return Status */
154     return Status;
155 }
156 
157 /*
158  * @implemented
159  */
160 NTSTATUS
161 NTAPI
NtOpenMutant(OUT PHANDLE MutantHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes)162 NtOpenMutant(OUT PHANDLE MutantHandle,
163              IN ACCESS_MASK DesiredAccess,
164              IN POBJECT_ATTRIBUTES ObjectAttributes)
165 {
166     HANDLE hMutant;
167     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
168     NTSTATUS Status;
169     PAGED_CODE();
170     DPRINT("NtOpenMutant(0x%p, 0x%x, 0x%p)\n",
171             MutantHandle, DesiredAccess, ObjectAttributes);
172 
173     /* Check if we were called from user-mode */
174     if (PreviousMode != KernelMode)
175     {
176         /* Enter SEH Block */
177         _SEH2_TRY
178         {
179             /* Check handle pointer */
180             ProbeForWriteHandle(MutantHandle);
181         }
182         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
183         {
184             /* Return the exception code */
185             _SEH2_YIELD(return _SEH2_GetExceptionCode());
186         }
187         _SEH2_END;
188     }
189 
190     /* Open the Object */
191     Status = ObOpenObjectByName(ObjectAttributes,
192                                 ExMutantObjectType,
193                                 PreviousMode,
194                                 NULL,
195                                 DesiredAccess,
196                                 NULL,
197                                 &hMutant);
198 
199     /* Check for success */
200     if(NT_SUCCESS(Status))
201     {
202         /* Enter SEH for return */
203         _SEH2_TRY
204         {
205             /* Return the handle to the caller */
206             *MutantHandle = hMutant;
207         }
208         _SEH2_EXCEPT(ExSystemExceptionFilter())
209         {
210             Status = _SEH2_GetExceptionCode();
211         }
212         _SEH2_END;
213     }
214 
215     /* Return Status */
216     return Status;
217 }
218 
219 /*
220  * @implemented
221  */
222 NTSTATUS
223 NTAPI
NtQueryMutant(IN HANDLE MutantHandle,IN MUTANT_INFORMATION_CLASS MutantInformationClass,OUT PVOID MutantInformation,IN ULONG MutantInformationLength,OUT PULONG ResultLength OPTIONAL)224 NtQueryMutant(IN HANDLE MutantHandle,
225               IN MUTANT_INFORMATION_CLASS MutantInformationClass,
226               OUT PVOID MutantInformation,
227               IN ULONG MutantInformationLength,
228               OUT PULONG ResultLength  OPTIONAL)
229 {
230     PKMUTANT Mutant;
231     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
232     NTSTATUS Status;
233     PMUTANT_BASIC_INFORMATION BasicInfo =
234         (PMUTANT_BASIC_INFORMATION)MutantInformation;
235     PAGED_CODE();
236 
237     /* Check buffers and parameters */
238     Status = DefaultQueryInfoBufferCheck(MutantInformationClass,
239                                          ExMutantInfoClass,
240                                          sizeof(ExMutantInfoClass) /
241                                          sizeof(ExMutantInfoClass[0]),
242                                          ICIF_PROBE_READ_WRITE,
243                                          MutantInformation,
244                                          MutantInformationLength,
245                                          ResultLength,
246                                          NULL,
247                                          PreviousMode);
248     if(!NT_SUCCESS(Status))
249     {
250         DPRINT("NtQueryMutant() failed, Status: 0x%x\n", Status);
251         return Status;
252     }
253 
254     /* Open the Object */
255     Status = ObReferenceObjectByHandle(MutantHandle,
256                                        MUTANT_QUERY_STATE,
257                                        ExMutantObjectType,
258                                        PreviousMode,
259                                        (PVOID*)&Mutant,
260                                        NULL);
261     /* Check for Status */
262     if (NT_SUCCESS(Status))
263     {
264         /* Enter SEH Block for return */
265          _SEH2_TRY
266          {
267             /* Fill out the Basic Information Requested */
268             DPRINT("Returning Mutant Information\n");
269             BasicInfo->CurrentCount = KeReadStateMutant(Mutant);
270             BasicInfo->OwnedByCaller = (Mutant->OwnerThread ==
271                                         KeGetCurrentThread());
272             BasicInfo->AbandonedState = Mutant->Abandoned;
273 
274             /* Return the Result Length if requested */
275            if (ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION);
276         }
277         _SEH2_EXCEPT(ExSystemExceptionFilter())
278         {
279             Status = _SEH2_GetExceptionCode();
280         }
281         _SEH2_END;
282 
283         /* Release the Object */
284         ObDereferenceObject(Mutant);
285     }
286 
287     /* Return Status */
288     return Status;
289 }
290 
291 /*
292  * @implemented
293  */
294 NTSTATUS
295 NTAPI
NtReleaseMutant(IN HANDLE MutantHandle,IN PLONG PreviousCount OPTIONAL)296 NtReleaseMutant(IN HANDLE MutantHandle,
297                 IN PLONG PreviousCount OPTIONAL)
298 {
299     PKMUTANT Mutant;
300     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
301     NTSTATUS Status;
302     PAGED_CODE();
303     DPRINT("NtReleaseMutant(MutantHandle 0x%p PreviousCount 0x%p)\n",
304             MutantHandle,
305             PreviousCount);
306 
307      /* Check if we were called from user-mode */
308     if ((PreviousCount) && (PreviousMode != KernelMode))
309     {
310         /* Entry SEH Block */
311         _SEH2_TRY
312         {
313             /* Make sure the state pointer is valid */
314             ProbeForWriteLong(PreviousCount);
315         }
316         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
317         {
318             /* Return the exception code */
319             _SEH2_YIELD(return _SEH2_GetExceptionCode());
320         }
321         _SEH2_END;
322     }
323 
324     /* Open the Object */
325     Status = ObReferenceObjectByHandle(MutantHandle,
326                                        0, /* No access rights required */
327                                        ExMutantObjectType,
328                                        PreviousMode,
329                                        (PVOID*)&Mutant,
330                                        NULL);
331 
332     /* Check for Success and release if such */
333     if (NT_SUCCESS(Status))
334     {
335         /*
336          * Release the mutant. doing so might raise an exception which we're
337          * required to catch!
338          */
339         _SEH2_TRY
340         {
341             /* Release the mutant */
342             LONG Prev = KeReleaseMutant(Mutant,
343                                         MUTANT_INCREMENT,
344                                         FALSE,
345                                         FALSE);
346 
347             /* Return the previous count if requested */
348             if (PreviousCount) *PreviousCount = Prev;
349         }
350         _SEH2_EXCEPT(ExSystemExceptionFilter())
351         {
352             /* Get the exception code */
353             Status = _SEH2_GetExceptionCode();
354         }
355         _SEH2_END;
356 
357         /* Dereference it */
358         ObDereferenceObject(Mutant);
359     }
360 
361     /* Return Status */
362     return Status;
363 }
364 
365 /* EOF */
366