From 5dce077e8610dc66de908aa765f872c93a28bce9 Mon Sep 17 00:00:00 2001 From: basil00 Date: Wed, 19 Oct 2011 20:53:49 +0800 Subject: [PATCH] - 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. --- build.sh | 7 +- doc/divert.html | 2 +- sys/divert.c | 196 ++++++++++++++++++++++++++++++------------------ 3 files changed, 130 insertions(+), 75 deletions(-) diff --git a/build.sh b/build.sh index 7f47c57..b1216db 100644 --- a/build.sh +++ b/build.sh @@ -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 diff --git a/doc/divert.html b/doc/divert.html index 445e79f..cb49714 100644 --- a/doc/divert.html +++ b/doc/divert.html @@ -826,7 +826,7 @@ Divert no traffic:
 HANDLE handle = DivertOpen("false");
 
-(This is not very useful). +This is useful for packet injection.
diff --git a/sys/divert.c b/sys/divert.c index 5a0e3b6..13f37e3 100644 --- a/sys/divert.c +++ b/sys/divert.c @@ -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: