ebpf-for-windows/netebpfext/net_ebpf_ext_prog_info_prov...

212 строки
8.9 KiB
C

// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#include "ebpf_extension_uuids.h"
#include "ebpf_platform.h"
#include "ebpf_program_types.h"
#include "net_ebpf_ext_prog_info_provider.h"
/**
* @brief This is the per client binding context for program information
* NPI provider.
*/
typedef struct _net_ebpf_extension_program_info_client
{
HANDLE nmr_binding_handle; ///< NMR binding handle.
GUID client_module_id; ///< NMR module ID.
ebpf_get_program_context_t get_program_context; ///< Pointer to function to get the program context.
net_ebpf_extension_program_info_provider_t* provider_context; ///< Pointer to the hook NPI provider context.
} net_ebpf_extension_program_info_client_t;
/**
* @brief This is the program information NPI provider.
*/
typedef struct _net_ebpf_extension_program_info_provider
{
NPI_PROVIDER_CHARACTERISTICS characteristics; ///< NPI Provider characteristics.
HANDLE nmr_provider_handle; ///< NMR binding handle.
net_ebpf_extension_program_info_on_client_attach
attach_callback; ///< Pointer to program info provider specific callback to be invoked when a client attaches.
net_ebpf_extension_program_info_on_client_detach
detach_callback; ///< Pointer to program info provider specific callback to be invoked when a client detaches.
} net_ebpf_extension_program_info_provider_t;
/**
* @brief Callback invoked when an eBPF Program Information NPI client attaches.
*
* @param[in] nmr_binding_handle NMR binding between the client module and the provider module.
* @param[in] provider_context Provider module's context.
* @param[in] client_registration_instance Client module's registration data.
* @param[in] client_binding_context Client module's context for binding with provider.
* @param[in] client_dispatch Client module's dispatch table. Contains the function pointer
* to invoke the eBPF program.
* @param[out] provider_binding_context Pointer to provider module's binding context with the client module.
* @param[out] provider_dispatch Pointer to provider module's dispatch table.
* @retval STATUS_SUCCESS The operation succeeded.
* @retval STATUS_NO_MEMORY Failed to allocate provider binding context.
* @retval STATUS_INVALID_PARAMETER One or more arguments are incorrect.
*/
static NTSTATUS
_net_ebpf_extension_program_info_provider_attach_client(
_In_ HANDLE nmr_binding_handle,
_In_ const void* provider_context,
_In_ const NPI_REGISTRATION_INSTANCE* client_registration_instance,
_In_ const void* client_binding_context,
_In_ const void* client_dispatch,
_Outptr_ void** provider_binding_context,
_Outptr_result_maybenull_ const void** provider_dispatch)
{
NTSTATUS status = STATUS_SUCCESS;
ebpf_result_t result;
net_ebpf_extension_program_info_provider_t* local_provider_context =
(net_ebpf_extension_program_info_provider_t*)provider_context;
net_ebpf_extension_program_info_client_t* program_info_client = NULL;
ebpf_extension_dispatch_table_t* client_dispatch_table;
NET_EBPF_EXT_LOG_ENTRY();
UNREFERENCED_PARAMETER(client_binding_context);
if ((provider_binding_context == NULL) || (provider_dispatch == NULL) || (local_provider_context == NULL)) {
status = STATUS_INVALID_PARAMETER;
goto Exit;
}
*provider_binding_context = NULL;
*provider_dispatch = NULL;
client_dispatch_table = (ebpf_extension_dispatch_table_t*)client_dispatch;
if (client_dispatch_table == NULL) {
status = STATUS_INVALID_PARAMETER;
goto Exit;
}
program_info_client = (net_ebpf_extension_program_info_client_t*)ExAllocatePoolUninitialized(
NonPagedPoolNx, sizeof(net_ebpf_extension_program_info_client_t), NET_EBPF_EXTENSION_POOL_TAG);
if (program_info_client == NULL) {
status = STATUS_NO_MEMORY;
goto Exit;
}
memset(program_info_client, 0, sizeof(net_ebpf_extension_program_info_client_t));
program_info_client->get_program_context = (ebpf_get_program_context_t)client_dispatch_table->function[0];
program_info_client->nmr_binding_handle = nmr_binding_handle;
program_info_client->client_module_id = client_registration_instance->ModuleId->Guid;
program_info_client->provider_context = local_provider_context;
if (local_provider_context->attach_callback) {
result = local_provider_context->attach_callback(program_info_client, local_provider_context);
if (result != EBPF_SUCCESS) {
status = STATUS_ACCESS_DENIED;
}
}
Exit:
if (NT_SUCCESS(status)) {
*provider_binding_context = program_info_client;
program_info_client = NULL;
} else {
if (program_info_client)
ExFreePool(program_info_client);
}
NET_EBPF_EXT_RETURN_NTSTATUS(status);
}
/**
* @brief Callback invoked when a Program Information NPI client detaches.
*
* @param[in] provider_binding_context Provider module's context for binding with the client.
* @retval STATUS_SUCCESS The operation succeeded.
* @retval STATUS_INVALID_PARAMETER One or more parameters are invalid.
*/
static NTSTATUS
_net_ebpf_extension_program_info_provider_detach_client(_In_ const void* provider_binding_context)
{
net_ebpf_extension_program_info_client_t* local_client_context =
(net_ebpf_extension_program_info_client_t*)provider_binding_context;
if (local_client_context == NULL) {
return STATUS_INVALID_PARAMETER;
}
net_ebpf_extension_program_info_provider_t* local_provider_context = local_client_context->provider_context;
if (local_provider_context->detach_callback) {
local_provider_context->detach_callback(local_client_context);
}
return STATUS_SUCCESS;
}
static void
_net_ebpf_extension_program_info_provider_cleanup_binding_context(_Frees_ptr_ void* provider_binding_context)
{
ExFreePool(provider_binding_context);
}
void
net_ebpf_extension_program_info_provider_unregister(
_Frees_ptr_opt_ net_ebpf_extension_program_info_provider_t* provider_context)
{
if (provider_context != NULL) {
NTSTATUS status = NmrDeregisterProvider(provider_context->nmr_provider_handle);
if (status == STATUS_PENDING)
NmrWaitForProviderDeregisterComplete(provider_context->nmr_provider_handle);
ExFreePool(provider_context);
}
}
NTSTATUS
net_ebpf_extension_program_info_provider_register(
_In_ const net_ebpf_extension_program_info_provider_parameters_t* parameters,
_In_opt_ net_ebpf_extension_program_info_on_client_attach attach_callback,
_In_opt_ net_ebpf_extension_program_info_on_client_detach detach_callback,
_Outptr_ net_ebpf_extension_program_info_provider_t** provider_context)
{
net_ebpf_extension_program_info_provider_t* local_provider_context = NULL;
NPI_PROVIDER_CHARACTERISTICS* characteristics;
NTSTATUS status = STATUS_SUCCESS;
NET_EBPF_EXT_LOG_ENTRY();
local_provider_context = (net_ebpf_extension_program_info_provider_t*)ExAllocatePoolUninitialized(
NonPagedPoolNx, sizeof(net_ebpf_extension_program_info_provider_t), NET_EBPF_EXTENSION_POOL_TAG);
if (local_provider_context == NULL) {
status = STATUS_NO_MEMORY;
goto Exit;
}
memset(local_provider_context, 0, sizeof(net_ebpf_extension_program_info_provider_t));
characteristics = &local_provider_context->characteristics;
characteristics->Length = sizeof(NPI_PROVIDER_CHARACTERISTICS);
characteristics->ProviderAttachClient =
(PNPI_PROVIDER_ATTACH_CLIENT_FN)_net_ebpf_extension_program_info_provider_attach_client;
characteristics->ProviderDetachClient =
(PNPI_PROVIDER_DETACH_CLIENT_FN)_net_ebpf_extension_program_info_provider_detach_client;
characteristics->ProviderCleanupBindingContext = _net_ebpf_extension_program_info_provider_cleanup_binding_context;
characteristics->ProviderRegistrationInstance.Size = sizeof(NPI_REGISTRATION_INSTANCE);
characteristics->ProviderRegistrationInstance.NpiId = &EBPF_PROGRAM_INFO_EXTENSION_IID;
characteristics->ProviderRegistrationInstance.NpiSpecificCharacteristics = parameters->provider_data;
characteristics->ProviderRegistrationInstance.ModuleId = parameters->provider_module_id;
local_provider_context->attach_callback = attach_callback;
local_provider_context->detach_callback = detach_callback;
status = NmrRegisterProvider(characteristics, local_provider_context, &local_provider_context->nmr_provider_handle);
if (!NT_SUCCESS(status))
goto Exit;
*provider_context = local_provider_context;
local_provider_context = NULL;
Exit:
if (!NT_SUCCESS(status))
net_ebpf_extension_program_info_provider_unregister(local_provider_context);
NET_EBPF_EXT_RETURN_NTSTATUS(status);
}
const ebpf_get_program_context_t
net_ebpf_extension_get_program_context_function(
_In_ const net_ebpf_extension_program_info_client_t* program_info_client)
{
return program_info_client->get_program_context;
}