[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH] Fix multiple completion vulnerability in transmit code



My previous patch 7c3365d5 "Make transmitter robust against a possible
completion race" did not fix the problem. There is still the possibility
that a NET_BUFFER_LIST containing multiple NET_BUFFERs could lead to
multiple completions if the underlying transmit completes quickly (or indeed
synchrnously). This is because a reference is taken before sending each
NET_BUFFER but, if that transmission completes immediately the reference is
dropped back to zero (leading to the NET_BUFFER_LIST being completed) before
the reference is taken for the next NET_BUFFER.

This patch therefore takes an extra reference before sending any NET_BUFFERs
and then drops it when there are no more NET_BUFFERs to send. This ensures
that the reference count on the NET_BUFFER_LIST can only fall to zero once
the whole thing has been processed.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 src/xennet/transmitter.c | 45 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 41 insertions(+), 4 deletions(-)

diff --git a/src/xennet/transmitter.c b/src/xennet/transmitter.c
index 91ed5f2..eaf5267 100644
--- a/src/xennet/transmitter.c
+++ b/src/xennet/transmitter.c
@@ -90,6 +90,7 @@ TransmitterTeardown(
 
 typedef struct _NET_BUFFER_LIST_RESERVED {
     LONG    Reference;
+    LONG    Status;
 } NET_BUFFER_LIST_RESERVED, *PNET_BUFFER_LIST_RESERVED;
 
 C_ASSERT(sizeof (NET_BUFFER_LIST_RESERVED) <= RTL_FIELD_SIZE(NET_BUFFER_LIST, 
MiniportReserved));
@@ -120,6 +121,39 @@ __TransmitterCompleteNetBufferList(
                                     NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
 }
 
+__TransmitterGetNetBufferList(
+    IN  PXENNET_TRANSMITTER     Transmitter,
+    IN  PNET_BUFFER_LIST        NetBufferList
+    )
+{
+    PNET_BUFFER_LIST_RESERVED   ListReserved;
+
+    UNREFERENCED_PARAMETER(Transmitter);
+
+    ListReserved = 
(PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList);
+
+    if (InterlockedIncrement(&ListReserved->Reference) == 1)
+        ListReserved->Status = NDIS_STATUS_PENDING;
+}
+
+__TransmitterPutNetBufferList(
+    IN  PXENNET_TRANSMITTER     Transmitter,
+    IN  PNET_BUFFER_LIST        NetBufferList
+    )
+{
+    PNET_BUFFER_LIST_RESERVED   ListReserved;
+
+    UNREFERENCED_PARAMETER(Transmitter);
+
+    ListReserved = 
(PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList);
+
+    ASSERT(ListReserved->Reference != 0);
+    if (InterlockedDecrement(&ListReserved->Reference) == 0)
+        __TransmitterCompleteNetBufferList(Transmitter,
+                                           NetBufferList,
+                                           ListReserved->Status);
+}
+
 static VOID
 __TransmitterReturnPacket(
     IN  PXENNET_TRANSMITTER     Transmitter,
@@ -134,9 +168,8 @@ __TransmitterReturnPacket(
 
     ListReserved = 
(PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList);
 
-    ASSERT(ListReserved->Reference != 0);
-    if (InterlockedDecrement(&ListReserved->Reference) == 0)
-        __TransmitterCompleteNetBufferList(Transmitter, NetBufferList, Status);
+    (VOID) InterlockedExchange(&ListReserved->Status, Status);
+    __TransmitterPutNetBufferList(Transmitter, NetBufferList);
 }
 
 static VOID
@@ -248,6 +281,8 @@ TransmitterSendNetBufferLists(
         ListReserved = 
(PNET_BUFFER_LIST_RESERVED)NET_BUFFER_LIST_MINIPORT_RESERVED(NetBufferList);
         RtlZeroMemory(ListReserved, sizeof (NET_BUFFER_LIST_RESERVED));
 
+        __TransmitterGetNetBufferList(Transmitter, NetBufferList);
+
         NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
         while (NetBuffer != NULL) {
             PNET_BUFFER         NetBufferListNext = 
NET_BUFFER_NEXT_NB(NetBuffer);
@@ -255,7 +290,7 @@ TransmitterSendNetBufferLists(
             XENVIF_PACKET_HASH  Hash;
             NTSTATUS            status;
 
-            InterlockedIncrement(&ListReserved->Reference);
+            __TransmitterGetNetBufferList(Transmitter, NetBufferList);
 
             Hash.Algorithm = XENVIF_PACKET_HASH_ALGORITHM_NONE;
 
@@ -278,6 +313,8 @@ TransmitterSendNetBufferLists(
             NetBuffer = NetBufferListNext;
         }
 
+        __TransmitterPutNetBufferList(Transmitter, NetBufferList);
+
         NetBufferList = ListNext;
     }
 
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.