From a59c70ae0a8eee63e608b566fd55366752558edf Mon Sep 17 00:00:00 2001 From: basil00 Date: Sat, 21 Sep 2013 10:43:42 +0800 Subject: [PATCH] - WinDivert now queues copies of packets, rather than simply referencing the original packet. The former turns out to be problematic, since there is no guarantee that something else (e.g. another callout driver) modifies/overwrites the packet data whilst it is in the queue. Copying the data is not ideal either, but seems to be the only way to ensure the packet is not changed later. --- sys/windivert.c | 53 +++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/sys/windivert.c b/sys/windivert.c index fe661a3..adbc486 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -192,9 +192,6 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(req_context_s, windivert_req_context_get); struct packet_s { LIST_ENTRY entry; // Entry for queue - PNET_BUFFER buffer; // The packet - PNET_BUFFER_LIST buffers; // The NBL contain the packet - PNET_BUFFER_LIST clone; // Clone of buffer UINT8 direction; // Packet direction UINT32 if_idx; // Interface index UINT32 sub_if_idx; // Sub-interface index @@ -202,6 +199,8 @@ struct packet_s BOOL tcp_checksum; // TCP checksum is valid BOOL udp_checksum; // UDP checksum is valid BOOL timer_ticktock; // Time-out ticktock + ULONG data_len; // Length of data + char data[]; // Packet data }; typedef struct packet_s *packet_t; #define WINDIVERT_NET_BUFFER_LIST_TAG 'Lvid' @@ -1210,18 +1209,10 @@ static void windivert_read_service(context_t context) goto windivert_read_service_complete; } dst_len = MmGetMdlByteCount(dst_mdl); - src_len = NET_BUFFER_DATA_LENGTH(packet->buffer); + src_len = packet->data_len; dst_len = (src_len < dst_len? src_len: dst_len); - src = NdisGetDataBuffer(packet->buffer, dst_len, NULL, 1, 0); - if (src == NULL) - { - NdisGetDataBuffer(packet->buffer, dst_len, dst, 1, 0); - } - else - { - RtlCopyMemory(dst, src, dst_len); - } - + RtlCopyMemory(dst, packet->data, dst_len); + // Write the address information. req_context = windivert_req_context_get(request); addr = req_context->addr; @@ -2060,6 +2051,8 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER_LIST buffers, KLOCK_QUEUE_HANDLE lock_handle; NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksum_info; PLIST_ENTRY entry; + ULONG length; + PVOID src; packet_t packet; NTSTATUS status; @@ -2068,36 +2061,28 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER_LIST buffers, return TRUE; } + length = NET_BUFFER_DATA_LENGTH(buffer); packet = (packet_t)ExAllocatePoolWithTag(NonPagedPool, - WINDIVERT_PACKET_SIZE, WINDIVERT_PACKET_TAG); + WINDIVERT_PACKET_SIZE + length, WINDIVERT_PACKET_TAG); if (packet == NULL) { return FALSE; } - if ((context->flags & WINDIVERT_FLAG_SNIFF) != 0) + // Copy the packet data + src = NdisGetDataBuffer(buffer, length, NULL, 1, 0); + if (src == NULL) { - // Clone the buffer - status = FwpsAllocateNetBufferAndNetBufferList0( - pool_handle, 0, 0, NET_BUFFER_FIRST_MDL(buffer), - NET_BUFFER_DATA_OFFSET(buffer), NET_BUFFER_DATA_LENGTH(buffer), - &packet->clone); - if (!NT_SUCCESS(status)) - { - ExFreePoolWithTag(packet, WINDIVERT_PACKET_TAG); - return FALSE; - } - buffer = NET_BUFFER_LIST_FIRST_NB(packet->clone); + NdisGetDataBuffer(buffer, length, packet->data, 1, 0); } else { - packet->clone = NULL; + RtlCopyMemory(packet->data, src, length); } - + packet->data_len = length; + checksum_info.Value = NET_BUFFER_LIST_INFO(buffers, TcpIpChecksumNetBufferListInfo); - packet->buffer = buffer; - packet->buffers = buffers; packet->direction = direction; packet->if_idx = if_idx; packet->sub_if_idx = sub_if_idx; @@ -2116,7 +2101,6 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER_LIST buffers, } packet->timer_ticktock = context->timer_ticktock; entry = &packet->entry; - FwpsReferenceNetBufferList0(buffers, FALSE); KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle); if (context->state != WINDIVERT_CONTEXT_STATE_OPEN) { @@ -2151,11 +2135,6 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER_LIST buffers, */ static void windivert_free_packet(packet_t packet) { - FwpsDereferenceNetBufferList0(packet->buffers, FALSE); - if (packet->clone != NULL) - { - FwpsFreeNetBufferList0(packet->clone); - } ExFreePoolWithTag(packet, WINDIVERT_PACKET_TAG); }