- 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.
This commit is contained in:
basil00
2013-09-21 10:43:42 +08:00
parent 0b15b26d45
commit a59c70ae0a
+16 -37
View File
@@ -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);
}