[ros-dev] KQUEUE race condition

Filip Navara xnavara at volny.cz
Sun Nov 21 01:54:44 CET 2004


Hi,

I think I found a race condition in KQUEUE code, but I'm not sure my 
solution is optimal. If no items are queued, KeRemoveQueue calls 
KeWaitForSingleObject and then after it finishes it acquires dispatcher 
lock and removes a list item. The problem arises when someone calls 
KeRemoveQueue just after the KeWaitForSingleObject call finishes and 
before the dispatcher lock is acquired. In this case he can remove the 
last item in the list and this will cause the first KeRemoveQueue (the 
one that waited) to return garbage. Can anybody think of better solution 
than the attached patch?

Regards,
Filip
-------------- next part --------------
Index: ntoskrnl/ke/queue.c
===================================================================
RCS file: /CVS/ReactOS/reactos/ntoskrnl/ke/queue.c,v
retrieving revision 1.11
diff -u -r1.11 queue.c
--- ntoskrnl/ke/queue.c	15 Aug 2004 16:39:05 -0000	1.11
+++ ntoskrnl/ke/queue.c	21 Nov 2004 00:39:52 -0000
@@ -159,27 +159,38 @@
       return ListEntry;
    }
 
-   //need to wait for it...
-   KeReleaseDispatcherDatabaseLock (OldIrql);
-
-   Status = KeWaitForSingleObject(Queue,
-                                  WrQueue,
-                                  WaitMode,
-                                  TRUE,//Alertable,
-                                  Timeout);
-
-   if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC)
-   {
-      return (PVOID)Status;
-   }
-   else
+   for (;;)
    {
-      OldIrql = KeAcquireDispatcherDatabaseLock ();
-      ListEntry = RemoveHeadList(&Queue->EntryListHead);
+      //need to wait for it...
       KeReleaseDispatcherDatabaseLock (OldIrql);
-      return ListEntry;
-   }
 
+      Status = KeWaitForSingleObject(Queue,
+                                     WrQueue,
+                                     WaitMode,
+                                     TRUE,//Alertable,
+                                     Timeout);
+
+      if (Status == STATUS_TIMEOUT || Status == STATUS_USER_APC)
+      {
+         return (PVOID)Status;
+      }
+      else
+      {
+         OldIrql = KeAcquireDispatcherDatabaseLock ();
+
+         /*
+          * Prevent a race condition. If someone calls KeRemoveQueue
+          * just after we end up waiting and before acquiring the spin
+          * lock he can get the last item in the list...
+          */
+         if (IsListEmpty(&Queue->EntryListHead))
+            continue;
+
+         ListEntry = RemoveHeadList(&Queue->EntryListHead);
+         KeReleaseDispatcherDatabaseLock (OldIrql);
+         return ListEntry;
+      }
+   }
 }
 
 


More information about the Ros-dev mailing list