From 92762a53897b93e20cfeb9e764b293b125929bd1 Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Fri, 9 Jan 2015 17:23:17 +0500 Subject: [PATCH] Driver: Add log buffer. --- src/drv/wipfbuf.c | 128 ++++++++++++++++++++++++++++++++++++++++++++-- src/drv/wipfdrv.c | 61 +++++++++++++++------- src/drv/wipfdrv.h | 7 ++- src/wipfconf.h | 2 +- src/wipfconfr.c | 3 +- src/wipflog.c | 29 +++++++++++ 6 files changed, 205 insertions(+), 25 deletions(-) create mode 100644 src/wipflog.c diff --git a/src/drv/wipfbuf.c b/src/drv/wipfbuf.c index eed85bf9..d86ea7f6 100644 --- a/src/drv/wipfbuf.c +++ b/src/drv/wipfbuf.c @@ -1,8 +1,18 @@ /* Windows IP Filter Log Buffer */ +#define WIPF_BUFFER_SIZE 4 * 1024 +#define WIPF_BUFFER_SIZE_MAX 32 * 1024 + +#include "../wipflog.c" + typedef struct wipf_buffer { UINT32 top, size; PVOID data; + + PIRP irp; /* pending */ + PVOID out; + ULONG out_len; + KSPIN_LOCK lock; } WIPF_BUFFER, *PWIPF_BUFFER; @@ -21,9 +31,121 @@ wipf_buffer_close (PWIPF_BUFFER buf) } } -static BOOL +static NTSTATUS wipf_buffer_write (PWIPF_BUFFER buf, UINT32 remote_ip, UINT64 pid, - UINT32 path_len, const PVOID path) + UINT32 path_len, const PVOID path, + PIRP *irp, NTSTATUS *irp_status, ULONG_PTR *info) { - return TRUE; + const UINT32 len = sizeof(UINT32) + sizeof(UINT64) + + sizeof(UINT32) + path_len; + UINT32 size; + KIRQL irq; + NTSTATUS status = STATUS_SUCCESS; + + KeAcquireSpinLock(&buf->lock, &irq); + + /* Try to directly write to pending client */ + if (buf->irp) { + *irp = buf->irp; + buf->irp = NULL; + + *info = len; + + if (buf->out_len < len) { + *irp_status = STATUS_BUFFER_TOO_SMALL; + /* fallback to buffer */ + } else { + wipf_log_write(buf->out, remote_ip, pid, path_len, path); + + *irp_status = STATUS_SUCCESS; + goto end; + } + } + + size = buf->size; + + if (len > WIPF_BUFFER_SIZE) { + status = STATUS_INVALID_PARAMETER; + goto end; /* drop too long path */ + } + if (len > size - buf->top) { + size *= 2; + } + if (size > WIPF_BUFFER_SIZE_MAX) { + status = STATUS_BUFFER_TOO_SMALL; + goto end; /* drop on overflow of buffer */ + } + + /* resize the buffer */ + if (size != buf->size) { + PVOID data = ExAllocatePoolWithTag(NonPagedPool, size, WIPF_POOL_TAG); + if (data == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto end; /* drop on OOM */ + } + + RtlCopyMemory(data, buf->data, buf->top); + wipf_buffer_close(buf); + + buf->data = data; + buf->size = size; + } + + buf->top += len; + + wipf_log_write(buf->data, remote_ip, pid, path_len, path); + + end: + KeReleaseSpinLock(&buf->lock, irq); + + return status; +} + +static NTSTATUS +wipf_buffer_xmove (PWIPF_BUFFER buf, PIRP irp, PVOID out, ULONG out_len, + ULONG_PTR *info) +{ + KIRQL irq; + NTSTATUS status = STATUS_SUCCESS; + + KeAcquireSpinLock(&buf->lock, &irq); + + *info = buf->top; + + if (!buf->top) { + if (buf->irp) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + buf->irp = irp; + buf->out = out; + buf->out_len = out_len; + status = STATUS_PENDING; + } + goto end; + } + + if (out_len < buf->top) { + status = STATUS_BUFFER_TOO_SMALL; + goto end; + } + + RtlCopyMemory(out, buf->data, buf->top); + buf->top = 0; + + end: + KeReleaseSpinLock(&buf->lock, irq); + + return status; +} + +static void +wipf_buffer_cancel_pending (PWIPF_BUFFER buf, PIRP irp) +{ + KIRQL irq; + + KeAcquireSpinLock(&buf->lock, &irq); + if (irp == buf->irp) { + buf->irp = NULL; + } + KeReleaseSpinLock(&buf->lock, irq); } diff --git a/src/drv/wipfdrv.c b/src/drv/wipfdrv.c index 68064bd1..b3a86b23 100644 --- a/src/drv/wipfdrv.c +++ b/src/drv/wipfdrv.c @@ -108,9 +108,8 @@ wipf_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, { PWIPF_CONF_REF conf_ref; UINT32 local_ip, remote_ip; - UINT64 pid; UINT32 path_len; - PVOID path = NULL; + PVOID path; BOOL blocked, notify; UNUSED(packet); @@ -123,12 +122,10 @@ wipf_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, local_ip = inFixedValues->incomingValue[localIpField].value.uint32; remote_ip = inFixedValues->incomingValue[remoteIpField].value.uint32; + path_len = inMetaValues->processPath->size; + path = inMetaValues->processPath->data; if (local_ip != remote_ip) { - pid = inMetaValues->processId; - path_len = inMetaValues->processPath->size; - path = inMetaValues->processPath->data; - blocked = wipf_conf_ipblocked(&conf_ref->conf, remote_ip, path_len, path, ¬ify); } else { @@ -144,8 +141,19 @@ wipf_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, } else { classifyOut->actionType = FWP_ACTION_CONTINUE; - if (notify) - wipf_buffer_write(&g_device->buffer, remote_ip, pid, path_len, path); + if (notify) { + PIRP irp = NULL; + NTSTATUS irp_status; + ULONG_PTR info; + + wipf_buffer_write(&g_device->buffer, remote_ip, + inMetaValues->processId, path_len, path, + &irp, &irp_status, &info); + + if (irp) { + wipf_request_complete_info(irp, irp_status, info); + } + } } return STATUS_SUCCESS; @@ -228,10 +236,23 @@ wipf_driver_complete (PDEVICE_OBJECT device, PIRP irp) return STATUS_SUCCESS; } +static void +wipf_driver_cancel_pending (PDEVICE_OBJECT device, PIRP irp) +{ + UNUSED(device); + + wipf_buffer_cancel_pending(&g_device->buffer, irp); + + IoReleaseCancelSpinLock(irp->CancelIrql); /* before IoCompleteRequest()! */ + + wipf_request_complete(irp, STATUS_CANCELLED); +} + static NTSTATUS wipf_driver_control (PDEVICE_OBJECT device, PIRP irp) { PIO_STACK_LOCATION irp_stack; + ULONG_PTR info = 0; NTSTATUS status = STATUS_INVALID_PARAMETER; UNUSED(device); @@ -255,23 +276,27 @@ wipf_driver_control (PDEVICE_OBJECT device, PIRP irp) } break; } -#if 0 case WIPF_IOCTL_GETLOG: { - PVOID data = irp->AssociatedIrp.SystemBuffer; - const ULONG len = irp_stack->Parameters.DeviceIoControl.OutputBufferLength; + PVOID out = irp->AssociatedIrp.SystemBuffer; + const ULONG out_len = irp_stack->Parameters.DeviceIoControl.OutputBufferLength; - status = wipf_buffer_read_result(&g_device->buffer, irp); + status = wipf_buffer_xmove(&g_device->buffer, irp, out, out_len, &info); + + if (status == STATUS_PENDING) { + KIRQL cirq; + + IoMarkIrpPending(irp); + + IoAcquireCancelSpinLock(&cirq); + IoSetCancelRoutine(irp, wipf_driver_cancel_pending); + IoReleaseCancelSpinLock(cirq); + } break; } -#endif default: break; } - if (!NT_SUCCESS(status)) { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "wipf: Control: Error: %d\n", status); - } - - wipf_request_complete(irp, status); + wipf_request_complete_info(irp, status, info); return status; } diff --git a/src/drv/wipfdrv.h b/src/drv/wipfdrv.h index 3cf5c944..df2e8af7 100644 --- a/src/drv/wipfdrv.h +++ b/src/drv/wipfdrv.h @@ -6,11 +6,14 @@ #define WIPF_POOL_TAG 'WIPF' -#define wipf_request_complete(irp, status) \ +#define wipf_request_complete_info(irp, status, info) \ do { \ (irp)->IoStatus.Status = (status); \ - (irp)->IoStatus.Information = 0; \ + (irp)->IoStatus.Information = (info); \ IoCompleteRequest((irp), IO_NO_INCREMENT); \ } while(0) +#define wipf_request_complete(irp, status) \ + wipf_request_complete_info((irp), (status), 0) + #endif WIPFDRV_H diff --git a/src/wipfconf.h b/src/wipfconf.h index b5cead39..95901fe1 100644 --- a/src/wipfconf.h +++ b/src/wipfconf.h @@ -3,7 +3,7 @@ typedef struct wipf_conf { UINT32 len; - UCHAR data[1]; + UCHAR data[4]; } WIPF_CONF, *PWIPF_CONF; #endif WIPFCONF_H diff --git a/src/wipfconfr.c b/src/wipfconfr.c index ef25ee8a..609e4978 100644 --- a/src/wipfconfr.c +++ b/src/wipfconfr.c @@ -7,6 +7,7 @@ static BOOL wipf_conf_ipblocked (const PWIPF_CONF conf, UINT32 remote_ip, UINT32 path_len, const PVOID path, PBOOL notify) { - return TRUE; + *notify = TRUE; + return FALSE; } diff --git a/src/wipflog.c b/src/wipflog.c new file mode 100644 index 00000000..cb36fc16 --- /dev/null +++ b/src/wipflog.c @@ -0,0 +1,29 @@ +/* Windows IP Filter Log */ + +static void +wipf_log_write (char *p, UINT32 remote_ip, UINT64 pid, + UINT32 path_len, const char *path) +{ + *((UINT32 *) p)++ = remote_ip; + *((UINT64 *) p)++ = pid; + *((UINT32 *) p)++ = path_len; + + if (path_len) { + RtlCopyMemory(p, path, path_len); + } +} + +static void +wipf_log_read (const char **p, UINT32 *remote_ip, UINT64 *pid, + UINT32 *path_len, const char **path) +{ + *remote_ip = *((UINT32 *) *p)++; + *pid = *((UINT64 *) *p)++; + *path_len = *((UINT32 *) *p)++; + + if (*path_len) { + *path = *p; + *p += *path_len; + } +} +