- Fix bug where WdfRequestProbeAndLockUserBufferFor* was not in the caller
context, resulting in an occasional BSOD. - Fix bug where the driver rejects the "false" filter. - Update documentation to reflect that the "false" filter is still useful for packet injection.
This commit is contained in:
@@ -24,13 +24,16 @@ ENVS="i586-mingw32msvc amd64-mingw32msvc"
|
||||
for ENV in $ENVS
|
||||
do
|
||||
CC="$ENV-gcc"
|
||||
STRIP="$ENV-strip"
|
||||
if [ -x "`which $CC`" ]
|
||||
then
|
||||
mkdir -p "install/$ENV"
|
||||
echo "$CC -Iinclude/ -c divert.o dll/divert.c"
|
||||
$CC -Iinclude/ -c divert.o dll/divert.c
|
||||
echo "$CC -O2 -Iinclude/ -c divert.o dll/divert.c"
|
||||
$CC -O2 -Iinclude/ -c divert.o dll/divert.c
|
||||
echo "$CC -shared -o install/$ENV/divert.dll divert.o"
|
||||
$CC -shared -o "install/$ENV/divert.dll" divert.o
|
||||
echo "$STRIP install/$ENV/divert.dll"
|
||||
$STRIP "install/$ENV/divert.dll"
|
||||
else
|
||||
echo "$CC: not found"
|
||||
fi
|
||||
|
||||
+1
-1
@@ -826,7 +826,7 @@ Divert no traffic:
|
||||
<pre>
|
||||
HANDLE handle = DivertOpen("false");
|
||||
</pre>
|
||||
(This is not very useful).
|
||||
This is useful for packet injection.
|
||||
</ol>
|
||||
|
||||
<hr>
|
||||
|
||||
+124
-72
@@ -30,6 +30,7 @@
|
||||
*/
|
||||
DRIVER_INITIALIZE DriverEntry;
|
||||
EVT_WDF_DRIVER_UNLOAD divert_unload;
|
||||
EVT_WDF_IO_IN_CALLER_CONTEXT divert_caller_context;
|
||||
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL divert_ioctl;
|
||||
EVT_WDF_DEVICE_FILE_CREATE divert_create;
|
||||
EVT_WDF_TIMER divert_timer;
|
||||
@@ -393,6 +394,8 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
|
||||
divert_cleanup);
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&obj_attrs, context_s);
|
||||
WdfDeviceInitSetFileObjectConfig(device_init, &file_config, &obj_attrs);
|
||||
WdfDeviceInitSetIoInCallerContextCallback(device_init,
|
||||
divert_caller_context);
|
||||
WDF_OBJECT_ATTRIBUTES_INIT(&obj_attrs);
|
||||
status = WdfDeviceCreate(&device_init, &obj_attrs, &device);
|
||||
if (!NT_SUCCESS(status))
|
||||
@@ -791,7 +794,8 @@ extern VOID divert_timer(IN WDFTIMER timer)
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("TIMER (context=%p, ticktock=%u)", context, context->timer_ticktock);
|
||||
// DEBUG("TIMER (context=%p, ticktock=%u)", context,
|
||||
// context->timer_ticktock);
|
||||
|
||||
// Sweep away old packets.
|
||||
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
|
||||
@@ -1143,6 +1147,119 @@ static void NTAPI divert_inject_complete(VOID *context,
|
||||
WdfRequestCompleteWithInformation(request, status, length);
|
||||
}
|
||||
|
||||
/*
|
||||
* Divert caller context preprocessing.
|
||||
*/
|
||||
VOID divert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
|
||||
{
|
||||
PCHAR inbuf;
|
||||
size_t inbuflen;
|
||||
WDF_REQUEST_PARAMETERS params;
|
||||
WDFMEMORY memobj;
|
||||
divert_addr_t addr;
|
||||
divert_ioctl_t ioctl;
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
req_context_t req_context = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
WDF_REQUEST_PARAMETERS_INIT(¶ms);
|
||||
WdfRequestGetParameters(request, ¶ms);
|
||||
|
||||
if (params.Type != WdfRequestTypeDeviceControl)
|
||||
{
|
||||
goto divert_caller_context_exit;
|
||||
}
|
||||
|
||||
// Get and verify the input buffer.
|
||||
status = WdfRequestRetrieveInputBuffer(request, 0, &inbuf, &inbuflen);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("failed to retrieve input buffer", status);
|
||||
goto divert_caller_context_error;
|
||||
}
|
||||
|
||||
if (inbuflen != sizeof(struct divert_ioctl_s))
|
||||
{
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("input buffer not an ioctl message header", status);
|
||||
goto divert_caller_context_error;
|
||||
}
|
||||
|
||||
ioctl = (divert_ioctl_t)inbuf;
|
||||
if (ioctl->version != DIVERT_VERSION || ioctl->magic != DIVERT_MAGIC ||
|
||||
ioctl->reserved != 0x0)
|
||||
{
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("input buffer contained a bad ioctl message header",
|
||||
status);
|
||||
goto divert_caller_context_error;
|
||||
}
|
||||
|
||||
// Probe and lock user buffers here (if required).
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, req_context_s);
|
||||
status = WdfObjectAllocateContext(request, &attributes, &req_context);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("failed to allocate request context for ioctl", status);
|
||||
goto divert_caller_context_error;
|
||||
}
|
||||
req_context->addr = NULL;
|
||||
if (ioctl->arg == (UINT64)NULL)
|
||||
{
|
||||
goto divert_caller_context_exit;
|
||||
}
|
||||
switch (params.Parameters.DeviceIoControl.IoControlCode)
|
||||
{
|
||||
case IOCTL_DIVERT_RECV:
|
||||
status = WdfRequestProbeAndLockUserBufferForWrite(request,
|
||||
(PVOID)ioctl->arg, sizeof(struct divert_addr_s), &memobj);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("invalid arg pointer for RECV ioctl", status);
|
||||
goto divert_caller_context_error;
|
||||
}
|
||||
addr = (divert_addr_t)WdfMemoryGetBuffer(memobj, NULL);
|
||||
break;
|
||||
|
||||
case IOCTL_DIVERT_SEND:
|
||||
status = WdfRequestProbeAndLockUserBufferForRead(request,
|
||||
(PVOID)ioctl->arg, sizeof(struct divert_addr_s), &memobj);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("invalid arg pointer for SEND ioctl", status);
|
||||
goto divert_caller_context_error;
|
||||
}
|
||||
addr = (divert_addr_t)WdfMemoryGetBuffer(memobj, NULL);
|
||||
break;
|
||||
|
||||
case IOCTL_DIVERT_SET_FILTER:
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("arg pointer is non-NULL for SET_FILTER ioctl",
|
||||
status);
|
||||
goto divert_caller_context_error;
|
||||
|
||||
default:
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("failed to complete I/O control; invalid request",
|
||||
status);
|
||||
goto divert_caller_context_error;
|
||||
}
|
||||
|
||||
req_context->addr = addr;
|
||||
|
||||
divert_caller_context_exit:
|
||||
|
||||
status = WdfDeviceEnqueueRequest(device, request);
|
||||
|
||||
divert_caller_context_error:
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("failed to enqueue request", status);
|
||||
WdfRequestComplete(request, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Divert I/O control.
|
||||
*/
|
||||
@@ -1153,10 +1270,8 @@ extern VOID divert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
|
||||
size_t inbuflen, outbuflen, filter_len;
|
||||
divert_ioctl_t ioctl;
|
||||
divert_ioctl_filter_t filter;
|
||||
WDFMEMORY memobj;
|
||||
divert_addr_t addr;
|
||||
WDF_OBJECT_ATTRIBUTES attributes;
|
||||
req_context_t req_context = NULL;
|
||||
req_context_t req_context;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
context_t context = divert_context_get(WdfRequestGetFileObject(request));
|
||||
UNREFERENCED_PARAMETER(queue);
|
||||
@@ -1176,34 +1291,16 @@ extern VOID divert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
|
||||
DEBUG_ERROR("failed to retrieve input buffer", status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
|
||||
if (inbuflen != sizeof(struct divert_ioctl_s) || inbuflen != in_length)
|
||||
{
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("input buffer not an ioctl message header", status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
|
||||
ioctl = (divert_ioctl_t)inbuf;
|
||||
if (ioctl->version != DIVERT_VERSION || ioctl->magic != DIVERT_MAGIC ||
|
||||
ioctl->reserved != 0x0)
|
||||
{
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("input buffer contained a bad ioctl message header",
|
||||
status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
|
||||
status = WdfRequestRetrieveOutputBuffer(request, 0, &outbuf, &outbuflen);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("failed to retrieve output buffer", status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
if (outbuflen != out_length)
|
||||
if (inbuflen != in_length || outbuflen != out_length)
|
||||
{
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("output buffer length mismatch", status);
|
||||
DEBUG_ERROR("buffer length mismatch", status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
|
||||
@@ -1211,34 +1308,6 @@ extern VOID divert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
|
||||
switch (code)
|
||||
{
|
||||
case IOCTL_DIVERT_RECV:
|
||||
if ((PVOID)ioctl->arg != NULL)
|
||||
{
|
||||
status = WdfRequestProbeAndLockUserBufferForWrite(request,
|
||||
(PVOID)ioctl->arg, sizeof(struct divert_addr_s), &memobj);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("invalid arg pointer for RECV ioctl", status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
addr = (divert_addr_t)WdfMemoryGetBuffer(memobj, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = NULL;
|
||||
}
|
||||
|
||||
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
|
||||
req_context_s);
|
||||
status = WdfObjectAllocateContext(request, &attributes,
|
||||
&req_context);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("failed to allocate request context for RECV "
|
||||
"ioctl", status);
|
||||
goto divert_ioctl_exit;
|
||||
|
||||
}
|
||||
req_context->addr = addr;
|
||||
status = divert_read(context, request);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
@@ -1247,14 +1316,9 @@ extern VOID divert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
|
||||
break;
|
||||
|
||||
case IOCTL_DIVERT_SEND:
|
||||
status = WdfRequestProbeAndLockUserBufferForRead(request,
|
||||
(PVOID)ioctl->arg, sizeof(struct divert_addr_s), &memobj);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("invalid arg pointer for SEND ioctl", status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
addr = (divert_addr_t)WdfMemoryGetBuffer(memobj, NULL);
|
||||
|
||||
req_context = divert_req_context_get(request);
|
||||
addr = req_context->addr;
|
||||
status = divert_write(context, request, addr);
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
@@ -1263,13 +1327,6 @@ extern VOID divert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
|
||||
break;
|
||||
|
||||
case IOCTL_DIVERT_SET_FILTER:
|
||||
if ((PVOID)ioctl->arg != NULL)
|
||||
{
|
||||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
DEBUG_ERROR("arg pointer is non-NULL for SET_FILTER ioctl",
|
||||
status);
|
||||
goto divert_ioctl_exit;
|
||||
}
|
||||
filter = (divert_ioctl_filter_t)outbuf;
|
||||
filter_len = outbuflen;
|
||||
if (!divert_filter_compile(filter, filter_len, context->filter))
|
||||
@@ -2313,11 +2370,6 @@ static BOOL divert_filter_compile(divert_ioctl_filter_t ioctl_filter,
|
||||
switch (ioctl_filter[i].field)
|
||||
{
|
||||
case DIVERT_FILTER_FIELD_ZERO:
|
||||
if (ioctl_filter[i].arg[0] != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case DIVERT_FILTER_FIELD_INBOUND:
|
||||
case DIVERT_FILTER_FIELD_OUTBOUND:
|
||||
case DIVERT_FILTER_FIELD_IP:
|
||||
|
||||
Reference in New Issue
Block a user