Defer filter list deletion to when deleting filter context, add debugging info and traces (#3300)

Co-authored-by: Dhiren Vispute <Dhiren.Vispute@microsoft.com>
This commit is contained in:
Dhiren Vispute 2024-03-08 08:38:54 -08:00 коммит произвёл GitHub
Родитель 00c6428dd5
Коммит 125c884ac4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
2 изменённых файлов: 56 добавлений и 17 удалений

Просмотреть файл

@ -280,8 +280,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 // 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. // with the filter context. This is best effort & no locks are held.
filter_context->client_detached = TRUE; filter_context->client_detached = TRUE;
filter_context->filter_ids = NULL;
filter_context->filter_ids_count = 0;
DEREFERENCE_FILTER_CONTEXT(filter_context); DEREFERENCE_FILTER_CONTEXT(filter_context);
} }
@ -353,18 +351,27 @@ net_ebpf_extension_get_callout_id_for_hook(net_ebpf_extension_hook_id_t hook_id)
return callout_id; return callout_id;
} }
void 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, _Frees_ptr_ _In_count_(filter_count) net_ebpf_ext_wfp_filter_id_t* filter_ids)
{ {
NET_EBPF_EXT_LOG_ENTRY(); NET_EBPF_EXT_LOG_ENTRY();
NTSTATUS status; NTSTATUS status = STATUS_SUCCESS;
for (uint32_t index = 0; index < filter_count; index++) { 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)) { if (!NT_SUCCESS(status)) {
NET_EBPF_EXT_LOG_NTSTATUS_API_FAILURE( NET_EBPF_EXT_LOG_NTSTATUS_API_FAILURE(
NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, "FwpmFilterDeleteById", status); NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, "FwpmFilterDeleteById", status);
} else {
filter_ids[index].state = NET_EBPF_EXT_WFP_FILTER_DELETED;
NET_EBPF_EXT_LOG_MESSAGE_UINT64_UINT64(
NET_EBPF_EXT_TRACELOG_LEVEL_VERBOSE,
NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION,
"Deleted WFP filter: ",
index,
filter_ids[index].id);
} }
} }
ExFreePool(filter_ids);
NET_EBPF_EXT_LOG_EXIT(); NET_EBPF_EXT_LOG_EXIT();
} }
@ -375,12 +382,12 @@ net_ebpf_extension_add_wfp_filters(
uint32_t condition_count, uint32_t condition_count,
_In_opt_count_(condition_count) const FWPM_FILTER_CONDITION* conditions, _In_opt_count_(condition_count) const FWPM_FILTER_CONDITION* conditions,
_Inout_ net_ebpf_extension_wfp_filter_context_t* filter_context, _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; NTSTATUS status = STATUS_SUCCESS;
ebpf_result_t result = EBPF_SUCCESS; ebpf_result_t result = EBPF_SUCCESS;
bool is_in_transaction = FALSE; 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; *filter_ids = NULL;
NET_EBPF_EXT_LOG_ENTRY(); NET_EBPF_EXT_LOG_ENTRY();
@ -392,12 +399,12 @@ net_ebpf_extension_add_wfp_filters(
goto Exit; goto Exit;
} }
local_filter_ids = (uint64_t*)ExAllocatePoolUninitialized( local_filter_ids = (net_ebpf_ext_wfp_filter_id_t*)ExAllocatePoolUninitialized(
NonPagedPoolNx, sizeof(uint64_t) * filter_count, NET_EBPF_EXTENSION_POOL_TAG); 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_BAIL_ON_ALLOC_FAILURE_RESULT(
NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, local_filter_ids, "local_filter_ids", 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));
status = FwpmTransactionBegin(_fwp_engine_handle, 0); status = FwpmTransactionBegin(_fwp_engine_handle, 0);
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
@ -409,6 +416,7 @@ net_ebpf_extension_add_wfp_filters(
for (uint32_t index = 0; index < filter_count; index++) { for (uint32_t index = 0; index < filter_count; index++) {
FWPM_FILTER filter = {0}; FWPM_FILTER filter = {0};
uint64_t local_filter_id = 0;
const net_ebpf_extension_wfp_filter_parameters_t* filter_parameter = &parameters[index]; const net_ebpf_extension_wfp_filter_parameters_t* filter_parameter = &parameters[index];
filter.layerKey = *filter_parameter->layer_guid; filter.layerKey = *filter_parameter->layer_guid;
@ -428,7 +436,7 @@ net_ebpf_extension_add_wfp_filters(
REFERENCE_FILTER_CONTEXT(filter_context); REFERENCE_FILTER_CONTEXT(filter_context);
filter.rawContext = (uint64_t)(uintptr_t)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_id);
if (!NT_SUCCESS(status)) { if (!NT_SUCCESS(status)) {
NET_EBPF_EXT_LOG_NTSTATUS_API_FAILURE_MESSAGE_STRING( NET_EBPF_EXT_LOG_NTSTATUS_API_FAILURE_MESSAGE_STRING(
NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION, NET_EBPF_EXT_TRACELOG_KEYWORD_EXTENSION,
@ -438,6 +446,16 @@ net_ebpf_extension_add_wfp_filters(
(char*)filter_parameter->name); (char*)filter_parameter->name);
result = EBPF_INVALID_ARGUMENT; result = EBPF_INVALID_ARGUMENT;
goto Exit; goto Exit;
} else {
local_filter_ids[index].id = local_filter_id;
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_EXTENSION,
"Added WFP filter: ",
index,
local_filter_id);
} }
} }

Просмотреть файл

@ -75,13 +75,30 @@ typedef struct _net_ebpf_extension_wfp_filter_parameters_array
/** /**
* "Base class" for all WFP filter contexts used by net ebpf extension hooks. * "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 typedef struct _net_ebpf_extension_wfp_filter_context
{ {
volatile long reference_count; ///< Reference count. volatile long reference_count; ///< Reference count.
const struct _net_ebpf_extension_hook_client* client_context; ///< Pointer to hook NPI client. 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. net_ebpf_ext_wfp_filter_id_t* filter_ids; ///< Array of WFP filter Ids.
bool client_detached : 1; ///< True if client has detached. 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; } net_ebpf_extension_wfp_filter_context_t;
#define REFERENCE_FILTER_CONTEXT(filter_context) \ #define REFERENCE_FILTER_CONTEXT(filter_context) \
@ -94,6 +111,9 @@ typedef struct _net_ebpf_extension_wfp_filter_context
if (InterlockedDecrement(&(filter_context)->reference_count) == 0) { \ if (InterlockedDecrement(&(filter_context)->reference_count) == 0) { \
net_ebpf_extension_hook_client_leave_rundown( \ net_ebpf_extension_hook_client_leave_rundown( \
(net_ebpf_extension_hook_client_t*)(filter_context)->client_context); \ (net_ebpf_extension_hook_client_t*)(filter_context)->client_context); \
if ((filter_context)->filter_ids != NULL) { \
ExFreePool((filter_context)->filter_ids); \
} \
ExFreePool((filter_context)); \ ExFreePool((filter_context)); \
} \ } \
} }
@ -193,7 +213,7 @@ net_ebpf_extension_add_wfp_filters(
uint32_t condition_count, uint32_t condition_count,
_In_opt_count_(condition_count) const FWPM_FILTER_CONDITION* conditions, _In_opt_count_(condition_count) const FWPM_FILTER_CONDITION* conditions,
_Inout_ net_ebpf_extension_wfp_filter_context_t* filter_context, _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. * @brief Deletes WFP filters with specified filter IDs.
@ -202,7 +222,8 @@ net_ebpf_extension_add_wfp_filters(
* @param[in] filter_ids ID of the filter being deleted. * @param[in] filter_ids ID of the filter being deleted.
*/ */
void 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, _Frees_ptr_ _In_count_(filter_count) net_ebpf_ext_wfp_filter_id_t* filter_ids);
// eBPF WFP Provider GUID. // eBPF WFP Provider GUID.
// ddb851f5-841a-4b77-8a46-bb7063e9f162 // ddb851f5-841a-4b77-8a46-bb7063e9f162