diff --git a/src/common/fortlog.c b/src/common/fortlog.c index ef14f97b..b3fd7eb1 100644 --- a/src/common/fortlog.c +++ b/src/common/fortlog.c @@ -5,7 +5,9 @@ #define FORT_LOG_ALIGN 4 #define FORT_LOG_FLAG_BLOCKED 0x01000000 -#define FORT_LOG_FLAG_STAT 0x02000000 +#define FORT_LOG_FLAG_PROC_NEW 0x02000000 +#define FORT_LOG_FLAG_PROC_DEL 0x04000000 +#define FORT_LOG_FLAG_STAT_TRAF 0x08000000 #define FORT_LOG_FLAG_TYPE_MASK 0xFF000000 #define FORT_LOG_BLOCKED_HEADER_SIZE (3 * sizeof(UINT32)) @@ -16,6 +18,16 @@ #define FORT_LOG_BLOCKED_SIZE_MAX FORT_LOG_BLOCKED_SIZE(FORT_LOG_PATH_MAX) +#define FORT_LOG_PROC_NEW_HEADER_SIZE (2 * sizeof(UINT32)) + +#define FORT_LOG_PROC_NEW_SIZE(path_len) \ + ((FORT_LOG_PROC_NEW_HEADER_SIZE + (path_len) \ + + (FORT_LOG_ALIGN - 1)) & ~(FORT_LOG_ALIGN - 1)) + +#define FORT_LOG_PROC_DEL_SIZE (2 * sizeof(UINT32)) + +#define FORT_LOG_SIZE_MAX FORT_LOG_BLOCKED_SIZE_MAX + #define fort_log_type(p) (*((UINT32 *) (p)) & FORT_LOG_FLAG_TYPE_MASK) @@ -53,11 +65,49 @@ fort_log_blocked_header_read (const char *p, UINT32 *remote_ip, UINT32 *pid, } static void -fort_log_blocked_read (const char *p, UINT32 *remote_ip, UINT32 *pid, - UINT32 *path_len, const char **path) +fort_log_proc_new_header_write (char *p, UINT32 pid, + UINT32 path_len) { - fort_log_blocked_header_read(p, remote_ip, pid, path_len); + UINT32 *up = (UINT32 *) p; - *path = p + FORT_LOG_BLOCKED_HEADER_SIZE; + *up++ = FORT_LOG_FLAG_PROC_NEW | path_len; + *up = pid; } +static void +fort_log_proc_new_write (char *p, UINT32 pid, + UINT32 path_len, const char *path) +{ + fort_log_proc_new_header_write(p, pid, path_len); + + if (path_len) { + RtlCopyMemory(p + FORT_LOG_PROC_NEW_HEADER_SIZE, path, path_len); + } +} + +static void +fort_log_proc_new_header_read (const char *p, UINT32 *pid, + UINT32 *path_len) +{ + UINT32 *up = (UINT32 *) p; + + *path_len = (*up++ & ~FORT_LOG_FLAG_TYPE_MASK); + *pid = *up; +} + +static void +fort_log_proc_del_write (char *p, UINT32 pid) +{ + UINT32 *up = (UINT32 *) p; + + *up++ = FORT_LOG_FLAG_PROC_DEL; + *up = pid; +} + +static void +fort_log_proc_del_read (const char *p, UINT32 *pid) +{ + UINT32 *up = (UINT32 *) p; + + *pid = *up; +} diff --git a/src/driver/fortbuf.c b/src/driver/fortbuf.c index 288ae5d4..84d7df0f 100644 --- a/src/driver/fortbuf.c +++ b/src/driver/fortbuf.c @@ -104,15 +104,60 @@ fort_buffer_close (PFORT_BUFFER buf) fort_buffer_data_del(buf->data_free); } +static NTSTATUS +fort_buffer_prepare (PFORT_BUFFER buf, UINT32 len, PCHAR *out, + PIRP *irp, NTSTATUS *irp_status, ULONG_PTR *info) +{ + /* Check pending buffer */ + if (buf->out_len && buf->out_top < buf->out_len) { + const UINT32 out_top = buf->out_top; + UINT32 new_top = out_top + len; + + /* Is it time to flush logs? */ + if (buf->out_len - new_top < FORT_LOG_SIZE_MAX) { + if (irp != NULL) { + buf->out_len = 0; + + *irp = buf->irp; + buf->irp = NULL; + + *irp_status = STATUS_SUCCESS; + + *info = new_top; + new_top = 0; + } else { + buf->out_len = out_top; + new_top = out_top; + } + } + + *out = buf->out + out_top; + buf->out_top = new_top; + } else { + PFORT_BUFFER_DATA data = fort_buffer_data_alloc(buf, len); + const UINT32 buf_top = data ? data->top : FORT_BUFFER_SIZE; + const UINT32 new_top = buf_top + len; + + if (new_top > FORT_BUFFER_SIZE) { + return STATUS_BUFFER_TOO_SMALL; /* drop on buffer overflow */ + } + + *out = data->p + buf_top; + data->top = new_top; + } + + return STATUS_SUCCESS; +} + static NTSTATUS fort_buffer_blocked_write (PFORT_BUFFER buf, UINT32 remote_ip, UINT32 pid, UINT32 path_len, const PVOID path, PIRP *irp, NTSTATUS *irp_status, ULONG_PTR *info) { - UINT32 len; PCHAR out; + UINT32 len; KLOCK_QUEUE_HANDLE lock_queue; - NTSTATUS status = STATUS_SUCCESS; + NTSTATUS status; if (path_len > FORT_LOG_PATH_MAX) { path_len = 0; /* drop too long path */ @@ -122,43 +167,64 @@ fort_buffer_blocked_write (PFORT_BUFFER buf, UINT32 remote_ip, UINT32 pid, KeAcquireInStackQueuedSpinLock(&buf->lock, &lock_queue); - /* Try to directly write to pending client */ - if (buf->out_len) { - const UINT32 out_top = buf->out_top; - UINT32 new_top = out_top + len; + status = fort_buffer_prepare(buf, len, &out, + irp, irp_status, info); - /* Is it time to flush logs? */ - if (buf->out_len - new_top < FORT_LOG_BLOCKED_SIZE_MAX) { - buf->out_len = 0; - - *irp = buf->irp; - buf->irp = NULL; - - *irp_status = STATUS_SUCCESS; - - *info = new_top; - new_top = 0; - } - - out = buf->out + out_top; - buf->out_top = new_top; - } else { - PFORT_BUFFER_DATA data = fort_buffer_data_alloc(buf, len); - const UINT32 buf_top = data ? data->top : FORT_BUFFER_SIZE; - const UINT32 new_top = buf_top + len; - - if (new_top > FORT_BUFFER_SIZE) { - status = STATUS_BUFFER_TOO_SMALL; - goto end; /* drop on buffer overflow */ - } - - out = data->p + buf_top; - data->top = new_top; + if (NT_SUCCESS(status)) { + fort_log_blocked_write(out, remote_ip, pid, path_len, path); } - fort_log_blocked_write(out, remote_ip, pid, path_len, path); + KeReleaseInStackQueuedSpinLock(&lock_queue); + + return status; +} + +static NTSTATUS +fort_buffer_proc_new_write (PFORT_BUFFER buf, UINT32 pid, + UINT32 path_len, const PVOID path, + PIRP *irp, NTSTATUS *irp_status, ULONG_PTR *info) +{ + PCHAR out; + UINT32 len; + KLOCK_QUEUE_HANDLE lock_queue; + NTSTATUS status; + + if (path_len > FORT_LOG_PATH_MAX) { + path_len = 0; /* drop too long path */ + } + + len = FORT_LOG_PROC_NEW_SIZE(path_len); + + KeAcquireInStackQueuedSpinLock(&buf->lock, &lock_queue); + + status = fort_buffer_prepare(buf, len, &out, + irp, irp_status, info); + + if (NT_SUCCESS(status)) { + fort_log_proc_new_write(out, pid, path_len, path); + } + + KeReleaseInStackQueuedSpinLock(&lock_queue); + + return status; +} + +static NTSTATUS +fort_buffer_proc_del_write (PFORT_BUFFER buf, UINT32 pid) +{ + PCHAR out; + const UINT32 len = FORT_LOG_PROC_DEL_SIZE; + KLOCK_QUEUE_HANDLE lock_queue; + NTSTATUS status; + + KeAcquireInStackQueuedSpinLock(&buf->lock, &lock_queue); + + status = fort_buffer_prepare(buf, len, &out, NULL, NULL, NULL); + + if (NT_SUCCESS(status)) { + fort_log_proc_del_write(out, pid); + } - end: KeReleaseInStackQueuedSpinLock(&lock_queue); return status; @@ -181,7 +247,7 @@ fort_buffer_xmove (PFORT_BUFFER buf, PIRP irp, PVOID out, ULONG out_len, if (!buf_top) { if (buf->out_len) { status = STATUS_INSUFFICIENT_RESOURCES; - } else if (out_len < FORT_LOG_BLOCKED_SIZE_MAX) { + } else if (out_len < FORT_LOG_SIZE_MAX) { status = STATUS_BUFFER_TOO_SMALL; } else { buf->irp = irp; diff --git a/src/driver/fortdrv.c b/src/driver/fortdrv.c index 73fb568b..ef741d58 100644 --- a/src/driver/fortdrv.c +++ b/src/driver/fortdrv.c @@ -172,10 +172,15 @@ fort_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, FORT_CONF_FLAGS conf_flags; UINT32 flags; UINT32 remote_ip; + UINT32 process_id; UINT32 path_len; PVOID path; BOOL ip_included, blocked; + PIRP irp = NULL; + ULONG_PTR info; + NTSTATUS irp_status; + UNUSED(layerData); UNUSED(flowContext); @@ -198,6 +203,7 @@ fort_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, goto permit; remote_ip = inFixedValues->incomingValue[remoteIpField].value.uint32; + process_id = (UINT32) inMetaValues->processId; path_len = inMetaValues->processPath->size - sizeof(WCHAR); // chop terminating zero path = inMetaValues->processPath->data; @@ -209,44 +215,44 @@ fort_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, if (!blocked) { if (ip_included && conf_flags.log_stat) { - fort_stat_flow_associate(&g_device->stat, inMetaValues->flowHandle, - g_device->flow4_id, (UINT32) inMetaValues->processId); + NTSTATUS status; + + status = fort_stat_flow_associate(&g_device->stat, + inMetaValues->flowHandle, g_device->flow4_id, process_id); + + if (NT_SUCCESS(status)) { + fort_buffer_proc_new_write(&g_device->buffer, + process_id, path_len, path, + &irp, &irp_status, &info); + } else if (status != STATUS_OBJECT_NAME_EXISTS) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, + "FORT: Classify v4: Flow assoc. error: %d\n", status); + } } goto permit; } if (conf_flags.log_blocked) { - PIRP irp = NULL; - ULONG_PTR info; - NTSTATUS irp_status, status; - - status = fort_buffer_blocked_write( - &g_device->buffer, remote_ip, - (UINT32) inMetaValues->processId, path_len, path, - &irp, &irp_status, &info); - - if (NT_SUCCESS(status)) { - if (irp != NULL) { - fort_request_complete_info(irp, irp_status, info); - } - } else { - DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, - "FORT: Classify v4: Log buffer error: %d (path len: %d)\n", - status, path_len); - } + fort_buffer_blocked_write(&g_device->buffer, + remote_ip, process_id, path_len, path, + &irp, &irp_status, &info); } block: classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; - return; + goto end; permit: classifyOut->actionType = FWP_ACTION_PERMIT; if ((filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)) { classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; } - return; + + end: + if (irp != NULL) { + fort_request_complete_info(irp, irp_status, info); + } } static void @@ -298,7 +304,11 @@ fort_callout_flow_delete_v4 (UINT16 layerId, UNUSED(layerId); UNUSED(calloutId); - fort_stat_flow_delete(&g_device->stat, flowContext); + if (NT_SUCCESS(fort_stat_flow_delete(&g_device->stat, flowContext))) { + const UINT32 process_id = (UINT32) flowContext; + + fort_buffer_proc_del_write(&g_device->buffer, process_id); + } } static void diff --git a/src/driver/fortstat.c b/src/driver/fortstat.c index 6b904d78..447fae79 100644 --- a/src/driver/fortstat.c +++ b/src/driver/fortstat.c @@ -46,23 +46,26 @@ fort_stat_proc_inc (PFORT_STAT stat, int proc_index) proc->refcount++; } -static void +static NTSTATUS fort_stat_proc_dec (PFORT_STAT stat, int proc_index) { PFORT_STAT_PROC proc = &stat->procs[proc_index]; if (--proc->refcount > 0) - return; + return STATUS_OBJECT_NAME_EXISTS; if (proc_index == stat->proc_top - 1) { + /* Chop from buffer */ stat->proc_top--; - return; + } else { + /* Add to free chain */ + proc->process_id = 0; + + proc->refcount = stat->proc_free_index; + stat->proc_free_index = proc_index; } - proc->process_id = 0; - - proc->refcount = stat->proc_free_index; - stat->proc_free_index = proc_index; + return STATUS_SUCCESS; } static void @@ -138,29 +141,34 @@ fort_stat_close (PFORT_STAT stat) } } -static void +static NTSTATUS fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id, UINT32 callout_id, UINT32 process_id) { KLOCK_QUEUE_HANDLE lock_queue; UINT64 flow_context; int proc_index; + NTSTATUS status; KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue); proc_index = fort_stat_proc_index(stat, process_id); if (proc_index == -1) { proc_index = fort_stat_proc_add(stat, process_id); - if (proc_index == -1) + if (proc_index == -1) { + status = STATUS_INSUFFICIENT_RESOURCES; goto end; + } } flow_context = (UINT64) process_id | ((UINT64) proc_index << 32); fort_stat_proc_inc(stat, proc_index); - if (!NT_SUCCESS(FwpsFlowAssociateContext0(flow_id, - FWPS_LAYER_STREAM_V4, callout_id, flow_context))) { + status = FwpsFlowAssociateContext0(flow_id, + FWPS_LAYER_STREAM_V4, callout_id, flow_context); + + if (!NT_SUCCESS(status)) { fort_stat_proc_dec(stat, proc_index); } @@ -169,22 +177,27 @@ fort_stat_flow_associate (PFORT_STAT stat, UINT64 flow_id, DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: flow +: %d\n", process_id); + + return status; } -static void +static NTSTATUS fort_stat_flow_delete (PFORT_STAT stat, UINT64 flow_context) { KLOCK_QUEUE_HANDLE lock_queue; + NTSTATUS status; const int proc_index = (int) (flow_context >> 32); KeAcquireInStackQueuedSpinLock(&stat->lock, &lock_queue); - fort_stat_proc_dec(stat, proc_index); + status = fort_stat_proc_dec(stat, proc_index); KeReleaseInStackQueuedSpinLock(&lock_queue); DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "FORT: flow -: %d\n", (UINT32) flow_context); + + return status; } static void diff --git a/src/ui/fortcommon.cpp b/src/ui/fortcommon.cpp index 3c06db48..3a0c7ac2 100644 --- a/src/ui/fortcommon.cpp +++ b/src/ui/fortcommon.cpp @@ -53,6 +53,21 @@ quint32 FortCommon::logBlockedSize(quint32 pathLen) return FORT_LOG_BLOCKED_SIZE(pathLen); } +quint32 FortCommon::logProcNewHeaderSize() +{ + return FORT_LOG_PROC_NEW_HEADER_SIZE; +} + +quint32 FortCommon::logProcNewSize(quint32 pathLen) +{ + return FORT_LOG_PROC_NEW_SIZE(pathLen); +} + +quint32 FortCommon::logProcDelSize() +{ + return FORT_LOG_PROC_DEL_SIZE; +} + quint32 FortCommon::logType(const char *input) { return fort_log_type(input); @@ -72,6 +87,28 @@ void FortCommon::logBlockedHeaderRead(const char *input, fort_log_blocked_header_read(input, remoteIp, pid, pathLen); } +void FortCommon::logProcNewHeaderWrite(char *output, + quint32 pid, quint32 pathLen) +{ + fort_log_proc_new_header_write(output, pid, pathLen); +} + +void FortCommon::logProcNewHeaderRead(const char *input, + quint32 *pid, quint32 *pathLen) +{ + fort_log_proc_new_header_read(input, pid, pathLen); +} + +void FortCommon::logProcDelWrite(char *output, quint32 pid) +{ + fort_log_proc_del_write(output, pid); +} + +void FortCommon::logProcDelRead(const char *input, quint32 *pid) +{ + fort_log_proc_del_read(input, pid); +} + void FortCommon::confAppPermsMaskInit(void *drvConf) { fort_conf_app_perms_mask_init((PFORT_CONF) drvConf); diff --git a/src/ui/fortcommon.h b/src/ui/fortcommon.h index c96d7cdc..f9f7c79e 100644 --- a/src/ui/fortcommon.h +++ b/src/ui/fortcommon.h @@ -22,6 +22,11 @@ public: static quint32 logBlockedHeaderSize(); static quint32 logBlockedSize(quint32 pathLen); + static quint32 logProcNewHeaderSize(); + static quint32 logProcNewSize(quint32 pathLen); + + static quint32 logProcDelSize(); + static quint32 logType(const char *input); static void logBlockedHeaderWrite(char *output, @@ -31,6 +36,14 @@ public: quint32 *remoteIp, quint32 *pid, quint32 *pathLen); + static void logProcNewHeaderWrite(char *output, + quint32 pid, quint32 pathLen); + static void logProcNewHeaderRead(const char *input, + quint32 *pid, quint32 *pathLen); + + static void logProcDelWrite(char *output, quint32 pid); + static void logProcDelRead(const char *input, quint32 *pid); + static void confAppPermsMaskInit(void *drvConf); static bool confIpInRange(const void *drvConf, quint32 ip, bool included = false);