From 3ce83ff94ac181a9176ef0544438e78a0f6143b6 Mon Sep 17 00:00:00 2001 From: Dhiren Vispute Date: Sat, 2 Mar 2024 17:19:28 -0800 Subject: [PATCH] WiP (Backup) - Add additional post-mortem debug info + traces --- netebpfext/net_ebpf_ext.c | 67 ++++++++++++++++++++++++----- netebpfext/net_ebpf_ext.h | 36 +++++++++++++--- netebpfext/net_ebpf_ext_bind.c | 2 +- netebpfext/net_ebpf_ext_sock_addr.c | 3 +- netebpfext/net_ebpf_ext_sock_ops.c | 3 +- netebpfext/net_ebpf_ext_xdp.c | 3 +- 6 files changed, 93 insertions(+), 21 deletions(-) diff --git a/netebpfext/net_ebpf_ext.c b/netebpfext/net_ebpf_ext.c index a403a0d923..5e25fd7fe0 100644 --- a/netebpfext/net_ebpf_ext.c +++ b/netebpfext/net_ebpf_ext.c @@ -253,6 +253,7 @@ net_ebpf_extension_wfp_filter_context_create( memset(local_filter_context, 0, filter_context_size); local_filter_context->reference_count = 1; // Initial reference. local_filter_context->client_context = client_context; + KeInitializeSpinLock(&local_filter_context->filter_ids_lock); if (!net_ebpf_extension_hook_client_enter_rundown( (net_ebpf_extension_hook_client_t*)local_filter_context->client_context)) { @@ -272,6 +273,20 @@ net_ebpf_extension_wfp_filter_context_create( NET_EBPF_EXT_RETURN_RESULT(result); } +void +net_ebpf_extension_wfp_filter_context_delete(_Frees_ptr_ net_ebpf_extension_wfp_filter_context_t* filter_context) +{ + if (filter_context) { + if (filter_context->filter_ids) { + ExFreePool(filter_context->filter_ids); + filter_context->filter_ids = NULL; + filter_context->filter_ids_count = 0; + } + + ExFreePool(filter_context); + } +} + void net_ebpf_extension_wfp_filter_context_cleanup(_Frees_ptr_ net_ebpf_extension_wfp_filter_context_t* filter_context) { @@ -280,8 +295,6 @@ net_ebpf_extension_wfp_filter_context_cleanup(_Frees_ptr_ net_ebpf_extension_wfp // lingering WFP classify callbacks will exit as it would not find any hook client associated // with the filter context. This is best effort & no locks are held. filter_context->client_detached = TRUE; - filter_context->filter_ids = NULL; - filter_context->filter_ids_count = 0; DEREFERENCE_FILTER_CONTEXT(filter_context); } @@ -353,18 +366,32 @@ net_ebpf_extension_get_callout_id_for_hook(net_ebpf_extension_hook_id_t hook_id) return callout_id; } void -net_ebpf_extension_delete_wfp_filters(uint32_t filter_count, _Frees_ptr_ _In_count_(filter_count) uint64_t* filter_ids) +net_ebpf_extension_delete_wfp_filters( + uint32_t filter_count, + _Inout_ net_ebpf_extension_wfp_filter_context_t* filter_context, + _Frees_ptr_ _In_count_(filter_count) net_ebpf_ext_wfp_filter_id_t* filter_ids) { NET_EBPF_EXT_LOG_ENTRY(); NTSTATUS status; + KIRQL old_irql = 0; + + KeAcquireSpinLock(&filter_context->filter_ids_lock, &old_irql); for (uint32_t index = 0; index < filter_count; index++) { - status = FwpmFilterDeleteById(_fwp_engine_handle, filter_ids[index]); + status = FwpmFilterDeleteById(_fwp_engine_handle, filter_ids[index].id); if (!NT_SUCCESS(status)) { NET_EBPF_EXT_LOG_NTSTATUS_API_FAILURE( NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, "FwpmFilterDeleteById", status); + } else { + filter_ids[index].state = NET_EBPF_EXT_WFP_FILTER_ADDED; + NET_EBPF_EXT_LOG_MESSAGE_UINT64_UINT64( + NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE, + NET_EBPF_EXT_TRACELOG_KEYWORD_BASE, + "Deleted WFP filter: ", + index, + filter_ids[index].id); } } - ExFreePool(filter_ids); + KeReleaseSpinLock(&filter_context->filter_ids_lock, old_irql); NET_EBPF_EXT_LOG_EXIT(); } @@ -375,13 +402,15 @@ net_ebpf_extension_add_wfp_filters( uint32_t condition_count, _In_opt_count_(condition_count) const FWPM_FILTER_CONDITION* conditions, _Inout_ net_ebpf_extension_wfp_filter_context_t* filter_context, - _Outptr_result_buffer_maybenull_(filter_count) uint64_t** filter_ids) + _Outptr_result_buffer_maybenull_(filter_count) net_ebpf_ext_wfp_filter_id_t** filter_ids) { NTSTATUS status = STATUS_SUCCESS; ebpf_result_t result = EBPF_SUCCESS; bool is_in_transaction = FALSE; - uint64_t* local_filter_ids = NULL; + net_ebpf_ext_wfp_filter_id_t* local_filter_ids = NULL; *filter_ids = NULL; + KIRQL old_irql = 0; + BOOL filter_ids_lock_acquired = FALSE; NET_EBPF_EXT_LOG_ENTRY(); @@ -392,12 +421,15 @@ net_ebpf_extension_add_wfp_filters( goto Exit; } - local_filter_ids = (uint64_t*)ExAllocatePoolUninitialized( - NonPagedPoolNx, sizeof(uint64_t) * filter_count, NET_EBPF_EXTENSION_POOL_TAG); + local_filter_ids = (net_ebpf_ext_wfp_filter_id_t*)ExAllocatePoolUninitialized( + NonPagedPoolNx, (sizeof(net_ebpf_ext_wfp_filter_id_t) * filter_count), NET_EBPF_EXTENSION_POOL_TAG); NET_EBPF_EXT_BAIL_ON_ALLOC_FAILURE_RESULT( NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, local_filter_ids, "local_filter_ids", result); - memset(local_filter_ids, 0, sizeof(uint64_t) * filter_count); + memset(local_filter_ids, 0, (sizeof(net_ebpf_ext_wfp_filter_id_t) * filter_count)); + + KeAcquireSpinLock(&filter_context->filter_ids_lock, &old_irql); + filter_ids_lock_acquired = TRUE; status = FwpmTransactionBegin(_fwp_engine_handle, 0); if (!NT_SUCCESS(status)) { @@ -428,7 +460,7 @@ net_ebpf_extension_add_wfp_filters( REFERENCE_FILTER_CONTEXT(filter_context); filter.rawContext = (uint64_t)(uintptr_t)filter_context; - status = FwpmFilterAdd(_fwp_engine_handle, &filter, NULL, &local_filter_ids[index]); + status = FwpmFilterAdd(_fwp_engine_handle, &filter, NULL, &local_filter_ids[index].id); if (!NT_SUCCESS(status)) { NET_EBPF_EXT_LOG_NTSTATUS_API_FAILURE_MESSAGE_STRING( NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, @@ -438,6 +470,15 @@ net_ebpf_extension_add_wfp_filters( (char*)filter_parameter->name); result = EBPF_INVALID_ARGUMENT; goto Exit; + } else { + local_filter_ids[index].name = (wchar_t*)filter_parameter->name; + local_filter_ids[index].state = NET_EBPF_EXT_WFP_FILTER_ADDED; + NET_EBPF_EXT_LOG_MESSAGE_UINT64_UINT64( + NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE, + NET_EBPF_EXT_TRACELOG_KEYWORD_BASE, + "Added WFP filter: ", + index, + local_filter_ids[index].id); } } @@ -465,6 +506,10 @@ net_ebpf_extension_add_wfp_filters( } } + if (filter_ids_lock_acquired) { + KeReleaseSpinLock(&filter_context->filter_ids_lock, old_irql); + } + NET_EBPF_EXT_RETURN_RESULT(result); } diff --git a/netebpfext/net_ebpf_ext.h b/netebpfext/net_ebpf_ext.h index 3b490df79e..17b8f7a307 100644 --- a/netebpfext/net_ebpf_ext.h +++ b/netebpfext/net_ebpf_ext.h @@ -75,13 +75,31 @@ typedef struct _net_ebpf_extension_wfp_filter_parameters_array /** * "Base class" for all WFP filter contexts used by net ebpf extension hooks. */ + +typedef enum _net_ebpf_ext_wfp_filter_state +{ + NET_EBPF_EXT_WFP_FILTER_ADDED = 1, + NET_EBPF_EXT_WFP_FILTER_DELETED = 2, + +} net_ebpf_ext_wfp_filter_state_t; + +typedef struct _net_ebpf_ext_wfp_filter_id +{ + wchar_t* name; + uint64_t id; + net_ebpf_ext_wfp_filter_state_t state; +} net_ebpf_ext_wfp_filter_id_t; + typedef struct _net_ebpf_extension_wfp_filter_context { volatile long reference_count; ///< Reference count. const struct _net_ebpf_extension_hook_client* client_context; ///< Pointer to hook NPI client. - uint64_t* filter_ids; ///< Array of WFP filter Ids. - uint32_t filter_ids_count; ///< Number of WFP filter Ids. - bool client_detached : 1; ///< True if client has detached. + + KSPIN_LOCK filter_ids_lock; ///< Lock for WFP filter id array synchronization. + net_ebpf_ext_wfp_filter_id_t* filter_ids; ///< Array of WFP filter Ids. + uint32_t filter_ids_count; ///< Number of WFP filter Ids. + + bool client_detached : 1; ///< True if client has detached. } net_ebpf_extension_wfp_filter_context_t; #define REFERENCE_FILTER_CONTEXT(filter_context) \ @@ -94,7 +112,7 @@ typedef struct _net_ebpf_extension_wfp_filter_context if (InterlockedDecrement(&(filter_context)->reference_count) == 0) { \ net_ebpf_extension_hook_client_leave_rundown( \ (net_ebpf_extension_hook_client_t*)(filter_context)->client_context); \ - ExFreePool((filter_context)); \ + net_ebpf_extension_wfp_filter_context_delete(filter_context); \ } \ } @@ -193,7 +211,7 @@ net_ebpf_extension_add_wfp_filters( uint32_t condition_count, _In_opt_count_(condition_count) const FWPM_FILTER_CONDITION* conditions, _Inout_ net_ebpf_extension_wfp_filter_context_t* filter_context, - _Outptr_result_buffer_maybenull_(filter_count) uint64_t** filter_ids); + _Outptr_result_buffer_maybenull_(filter_count) net_ebpf_ext_wfp_filter_id_t** filter_ids); /** * @brief Deletes WFP filters with specified filter IDs. @@ -202,7 +220,10 @@ net_ebpf_extension_add_wfp_filters( * @param[in] filter_ids ID of the filter being deleted. */ void -net_ebpf_extension_delete_wfp_filters(uint32_t filter_count, _Frees_ptr_ _In_count_(filter_count) uint64_t* filter_ids); +net_ebpf_extension_delete_wfp_filters( + uint32_t filter_count, + _Inout_ net_ebpf_extension_wfp_filter_context_t* filter_context, + _Frees_ptr_ _In_count_(filter_count) net_ebpf_ext_wfp_filter_id_t* filter_ids); // eBPF WFP Provider GUID. // ddb851f5-841a-4b77-8a46-bb7063e9f162 @@ -274,3 +295,6 @@ net_ebpf_ext_unregister_providers(); NTSTATUS net_ebpf_ext_filter_change_notify( FWPS_CALLOUT_NOTIFY_TYPE callout_notification_type, _In_ const GUID* filter_key, _Inout_ FWPS_FILTER* filter); + +void +net_ebpf_extension_wfp_filter_context_delete(_Frees_ptr_ net_ebpf_extension_wfp_filter_context_t* filter_context); diff --git a/netebpfext/net_ebpf_ext_bind.c b/netebpfext/net_ebpf_ext_bind.c index 1c65c291c2..097d941801 100644 --- a/netebpfext/net_ebpf_ext_bind.c +++ b/netebpfext/net_ebpf_ext_bind.c @@ -143,7 +143,7 @@ _net_ebpf_extension_bind_on_client_detach(_In_ const net_ebpf_extension_hook_cli ASSERT(filter_context != NULL); // Delete the WFP filters. - net_ebpf_extension_delete_wfp_filters(filter_context->filter_ids_count, filter_context->filter_ids); + net_ebpf_extension_delete_wfp_filters(filter_context->filter_ids_count, filter_context, filter_context->filter_ids); net_ebpf_extension_wfp_filter_context_cleanup((net_ebpf_extension_wfp_filter_context_t*)filter_context); } diff --git a/netebpfext/net_ebpf_ext_sock_addr.c b/netebpfext/net_ebpf_ext_sock_addr.c index dbbd1b7c57..bdc1b504c2 100644 --- a/netebpfext/net_ebpf_ext_sock_addr.c +++ b/netebpfext/net_ebpf_ext_sock_addr.c @@ -640,7 +640,8 @@ _net_ebpf_extension_sock_addr_on_client_detach(_In_ const net_ebpf_extension_hoo (net_ebpf_extension_sock_addr_wfp_filter_context_t*)net_ebpf_extension_hook_client_get_provider_data( detaching_client); ASSERT(filter_context != NULL); - net_ebpf_extension_delete_wfp_filters(filter_context->base.filter_ids_count, filter_context->base.filter_ids); + net_ebpf_extension_delete_wfp_filters( + filter_context->base.filter_ids_count, &filter_context->base, filter_context->base.filter_ids); if (filter_context->redirect_handle != NULL) { FwpsRedirectHandleDestroy(filter_context->redirect_handle); } diff --git a/netebpfext/net_ebpf_ext_sock_ops.c b/netebpfext/net_ebpf_ext_sock_ops.c index 12a577399a..1677ae1ef3 100644 --- a/netebpfext/net_ebpf_ext_sock_ops.c +++ b/netebpfext/net_ebpf_ext_sock_ops.c @@ -214,7 +214,8 @@ _net_ebpf_extension_sock_ops_on_client_detach(_In_ const net_ebpf_extension_hook ASSERT(filter_context != NULL); InitializeListHead(&local_list_head); - net_ebpf_extension_delete_wfp_filters(filter_context->base.filter_ids_count, filter_context->base.filter_ids); + net_ebpf_extension_delete_wfp_filters( + filter_context->base.filter_ids_count, &filter_context->base, filter_context->base.filter_ids); KeAcquireSpinLock(&filter_context->lock, &irql); if (filter_context->flow_context_list.count > 0) { diff --git a/netebpfext/net_ebpf_ext_xdp.c b/netebpfext/net_ebpf_ext_xdp.c index a9e68e8389..304c76002f 100644 --- a/netebpfext/net_ebpf_ext_xdp.c +++ b/netebpfext/net_ebpf_ext_xdp.c @@ -239,7 +239,8 @@ _net_ebpf_extension_xdp_on_client_detach(_In_ const net_ebpf_extension_hook_clie NET_EBPF_EXT_LOG_ENTRY(); ASSERT(filter_context != NULL); - net_ebpf_extension_delete_wfp_filters(filter_context->base.filter_ids_count, filter_context->base.filter_ids); + net_ebpf_extension_delete_wfp_filters( + filter_context->base.filter_ids_count, &filter_context->base, filter_context->base.filter_ids); net_ebpf_extension_wfp_filter_context_cleanup((net_ebpf_extension_wfp_filter_context_t*)filter_context); NET_EBPF_EXT_LOG_EXIT();