Implement eBPF extension and provider loading functionality (#90)
* Add support for invoking NMR to register client and providers. Load global helper functions as extensions. Create user-mode mocks to test extension loading. Resolves: #80 Signed-off-by: Alan Jowett <alanjo@microsoft.com>
This commit is contained in:
Родитель
68cc22c090
Коммит
0b0eaca37c
|
@ -266,7 +266,7 @@ extern "C"
|
||||||
ebpf_api_unpin_map(const uint8_t* name, uint32_t name_length);
|
ebpf_api_unpin_map(const uint8_t* name, uint32_t name_length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Find a map given it's associated name.
|
* @brief Find a map given its associated name.
|
||||||
* @param[in] name Name to find.
|
* @param[in] name Name to find.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
|
|
|
@ -14,6 +14,8 @@ extern "C"
|
||||||
#endif
|
#endif
|
||||||
#include "ebpf_protocol.h"
|
#include "ebpf_protocol.h"
|
||||||
|
|
||||||
|
extern GUID ebpf_global_helper_function_interface_id;
|
||||||
|
|
||||||
typedef uint32_t(__stdcall* ebpf_hook_function)(uint8_t*);
|
typedef uint32_t(__stdcall* ebpf_hook_function)(uint8_t*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,23 +84,6 @@ extern "C"
|
||||||
ebpf_core_get_protocol_handler_properties(
|
ebpf_core_get_protocol_handler_properties(
|
||||||
ebpf_operation_id_t operation_id, _Out_ size_t* minimum_request_size, _Out_ size_t* minimum_reply_size);
|
ebpf_operation_id_t operation_id, _Out_ size_t* minimum_request_size, _Out_ size_t* minimum_reply_size);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the count of global helper functions.
|
|
||||||
*
|
|
||||||
* @return Count of global helper functions.
|
|
||||||
*/
|
|
||||||
size_t
|
|
||||||
ebpf_core_get_global_helper_count();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the address of a global helper function.
|
|
||||||
*
|
|
||||||
* @param[in] helper_id Id of the global helper function.
|
|
||||||
* @return Address of the global helper function.
|
|
||||||
*/
|
|
||||||
const void*
|
|
||||||
ebpf_core_get_global_helper(size_t helper_id);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -42,13 +42,22 @@ extern "C"
|
||||||
typedef struct _epbf_non_preemptible_work_item epbf_non_preemptible_work_item_t;
|
typedef struct _epbf_non_preemptible_work_item epbf_non_preemptible_work_item_t;
|
||||||
typedef struct _ebpf_timer_work_item ebpf_timer_work_item_t;
|
typedef struct _ebpf_timer_work_item ebpf_timer_work_item_t;
|
||||||
typedef struct _ebpf_extension_client ebpf_extension_client_t;
|
typedef struct _ebpf_extension_client ebpf_extension_client_t;
|
||||||
|
typedef struct _ebpf_extension_provider ebpf_extension_provider_t;
|
||||||
typedef ebpf_error_code_t (*_ebpf_extension_dispatch_function)();
|
typedef ebpf_error_code_t (*_ebpf_extension_dispatch_function)();
|
||||||
typedef struct _ebpf_extension_dispatch_table
|
typedef struct _ebpf_extension_dispatch_table
|
||||||
{
|
{
|
||||||
size_t size;
|
uint16_t version;
|
||||||
|
uint16_t size;
|
||||||
_ebpf_extension_dispatch_function function[1];
|
_ebpf_extension_dispatch_function function[1];
|
||||||
} ebpf_extension_dispatch_table_t;
|
} ebpf_extension_dispatch_table_t;
|
||||||
|
|
||||||
|
typedef struct _ebpf_extension_data
|
||||||
|
{
|
||||||
|
uint16_t version;
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t data[1];
|
||||||
|
} ebpf_extension_data_t;
|
||||||
|
|
||||||
#define EBPF_LOCK_SIZE sizeof(uint64_t)
|
#define EBPF_LOCK_SIZE sizeof(uint64_t)
|
||||||
#define EBPF_LOCK_STATE_SIZE sizeof(uint64_t)
|
#define EBPF_LOCK_STATE_SIZE sizeof(uint64_t)
|
||||||
typedef uint8_t ebpf_lock_t[EBPF_LOCK_SIZE];
|
typedef uint8_t ebpf_lock_t[EBPF_LOCK_SIZE];
|
||||||
|
@ -425,18 +434,18 @@ extern "C"
|
||||||
ebpf_interlocked_compare_exchange_int32(volatile int32_t* destination, int32_t exchange, int32_t comperand);
|
ebpf_interlocked_compare_exchange_int32(volatile int32_t* destination, int32_t exchange, int32_t comperand);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load an extension and get it's dispatch table.
|
* @brief Load an extension and get its dispatch table.
|
||||||
*
|
*
|
||||||
* @param[out] client_context Context used to unload the extension.
|
* @param[out] client_context Context used to unload the extension.
|
||||||
* @param[in] client_id GUID representing the identity of the client.
|
* @param[in] interface_id GUID representing the identity of the interface.
|
||||||
|
* @param[in] client_binding_context Opaque per-instance pointer passed to the extension.
|
||||||
* @param[in] client_data Opaque client data passed to the extension.
|
* @param[in] client_data Opaque client data passed to the extension.
|
||||||
* @param[in] client_data_length Length of the client data.
|
* @param[in] client_data_length Length of the client data.
|
||||||
* @param[in] client_dispatch_table Table of function pointers the client
|
* @param[in] client_dispatch_table Table of function pointers the client
|
||||||
* exposes.
|
* exposes.
|
||||||
* @param[in] provider_id GUID representing the extension to load.
|
* @param[in] provider_id GUID representing the extension to load.
|
||||||
* @param[out] provider_data Opaque provider data.
|
* @param[out] provider_data Opaque provider data.
|
||||||
* @param[out] provider_data_length Length of the provider data.
|
* @param[out] provider_dispatch_table Table of function pointers the
|
||||||
* @param[out] provider_dispatch_table Table of function pointer the
|
|
||||||
* provider exposes.
|
* provider exposes.
|
||||||
* @retval EBPF_ERROR_SUCCESS The operation was successful.
|
* @retval EBPF_ERROR_SUCCESS The operation was successful.
|
||||||
* @retval EBPF_ERROR_NOT_FOUND The provider was not found.
|
* @retval EBPF_ERROR_NOT_FOUND The provider was not found.
|
||||||
|
@ -446,13 +455,12 @@ extern "C"
|
||||||
ebpf_error_code_t
|
ebpf_error_code_t
|
||||||
ebpf_extension_load(
|
ebpf_extension_load(
|
||||||
ebpf_extension_client_t** client_context,
|
ebpf_extension_client_t** client_context,
|
||||||
const GUID* client_id,
|
const GUID* interface_id,
|
||||||
const uint8_t* client_data,
|
void* client_binding_context,
|
||||||
size_t client_data_length,
|
const ebpf_extension_data_t* client_data,
|
||||||
const ebpf_extension_dispatch_table_t* client_dispatch_table,
|
const ebpf_extension_dispatch_table_t* client_dispatch_table,
|
||||||
const GUID* provider_id,
|
void** provider_binding_context,
|
||||||
uint8_t** provider_data,
|
ebpf_extension_data_t** provider_data,
|
||||||
size_t* provider_data_length,
|
|
||||||
ebpf_extension_dispatch_table_t** provider_dispatch_table);
|
ebpf_extension_dispatch_table_t** provider_dispatch_table);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -463,6 +471,51 @@ extern "C"
|
||||||
void
|
void
|
||||||
ebpf_extension_unload(ebpf_extension_client_t* client_context);
|
ebpf_extension_unload(ebpf_extension_client_t* client_context);
|
||||||
|
|
||||||
|
typedef ebpf_error_code_t (*ebpf_provider_client_attach_callback_t)(
|
||||||
|
const GUID* client_id,
|
||||||
|
void* client_binding_context,
|
||||||
|
const ebpf_extension_data_t* client_data,
|
||||||
|
const ebpf_extension_dispatch_table_t* client_dispatch_table);
|
||||||
|
|
||||||
|
typedef ebpf_error_code_t (*ebpf_provider_client_detach_callback_t)(const GUID* client_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register as an extension provider.
|
||||||
|
*
|
||||||
|
* @param[out] provider_context Context used to unload the provider.
|
||||||
|
* @param[in] interface_id GUID representing the identity of the interface.
|
||||||
|
* @param[in] provider_data Opaque provider data.
|
||||||
|
* @param[in] provider_dispatch_table Table of function pointers the
|
||||||
|
* provider exposes.
|
||||||
|
* @param[in] client_attach_callback Function invoked when a client attaches.
|
||||||
|
* @param[in] client_detach_callback Function invoked when a client detaches.
|
||||||
|
* @retval EBPF_ERROR_SUCCESS The operation was successful.
|
||||||
|
* @retval EBPF_ERROR_EXTENSION_FAILED_TO_LOAD The provider was unable to
|
||||||
|
* load.
|
||||||
|
* @retval EBPF_ERROR_OUT_OF_RESOURCES Unable to allocate resources for this
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
ebpf_error_code_t
|
||||||
|
ebpf_provider_load(
|
||||||
|
ebpf_extension_provider_t** provider_context,
|
||||||
|
const GUID* interface_id,
|
||||||
|
void* provider_binding_context,
|
||||||
|
const ebpf_extension_data_t* provider_data,
|
||||||
|
const ebpf_extension_dispatch_table_t* provider_dispatch_table,
|
||||||
|
ebpf_provider_client_attach_callback_t client_attach_callback,
|
||||||
|
ebpf_provider_client_detach_callback_t client_detach_callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unload a provider.
|
||||||
|
*
|
||||||
|
* @param[in] provider_context Provider to unload.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
epbf_provider_unload(ebpf_extension_provider_t* provider_context);
|
||||||
|
|
||||||
|
ebpf_error_code_t
|
||||||
|
ebpf_guid_create(GUID* new_guid);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,6 +40,7 @@ typedef enum _ebpf_error_code
|
||||||
EBPF_ERROR_NOT_SUPPORTED,
|
EBPF_ERROR_NOT_SUPPORTED,
|
||||||
EBPF_ERROR_DUPLICATE_NAME,
|
EBPF_ERROR_DUPLICATE_NAME,
|
||||||
EBPF_ERROR_ARITHMETIC_OVERFLOW,
|
EBPF_ERROR_ARITHMETIC_OVERFLOW,
|
||||||
|
EBPF_ERROR_EXTENSION_FAILED_TO_LOAD,
|
||||||
} ebpf_error_code_t;
|
} ebpf_error_code_t;
|
||||||
|
|
||||||
typedef struct _ebpf_map_definition
|
typedef struct _ebpf_map_definition
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <ntstatus.h>
|
#include <ntstatus.h>
|
||||||
#include <ntintsafe.h>
|
#include <ntintsafe.h>
|
||||||
#include <ntddk.h>
|
#include <ntddk.h>
|
||||||
|
#include <netioddk.h>
|
||||||
#define uint8_t UINT8
|
#define uint8_t UINT8
|
||||||
#define uint16_t UINT16
|
#define uint16_t UINT16
|
||||||
#define uint32_t UINT32
|
#define uint32_t UINT32
|
||||||
|
@ -27,4 +28,4 @@
|
||||||
#define ebpf_list_initialize InitializeListHead
|
#define ebpf_list_initialize InitializeListHead
|
||||||
#define ebpf_list_is_empty IsListEmpty
|
#define ebpf_list_is_empty IsListEmpty
|
||||||
#define ebpf_list_insert_tail InsertTailList
|
#define ebpf_list_insert_tail InsertTailList
|
||||||
#define ebpf_list_remove_entry RemoveEntryList
|
#define ebpf_list_remove_entry RemoveEntryList
|
||||||
|
|
|
@ -12,9 +12,12 @@
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||||
// Windows Header Files
|
// Windows Header Files
|
||||||
|
#include <rpc.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winioctl.h>
|
#include <winioctl.h>
|
||||||
|
|
||||||
|
#pragma comment(lib, "rpcrt4")
|
||||||
|
|
||||||
#define ebpf_assert(x) assert(x)
|
#define ebpf_assert(x) assert(x)
|
||||||
|
|
||||||
#if !defined(UNREFERENCED_PARAMETER)
|
#if !defined(UNREFERENCED_PARAMETER)
|
||||||
|
|
|
@ -11,6 +11,15 @@
|
||||||
#include "ebpf_pinning_table.h"
|
#include "ebpf_pinning_table.h"
|
||||||
#include "ebpf_program.h"
|
#include "ebpf_program.h"
|
||||||
|
|
||||||
|
GUID ebpf_global_helper_function_interface_id = {/* 8d2a1d3f-9ce6-473d-b48e-17aa5c5581fe */
|
||||||
|
0x8d2a1d3f,
|
||||||
|
0x9ce6,
|
||||||
|
0x473d,
|
||||||
|
{0xb4, 0x8e, 0x17, 0xaa, 0x5c, 0x55, 0x81, 0xfe}};
|
||||||
|
|
||||||
|
static ebpf_extension_dispatch_table_t* _ebpf_global_helper_function_dispatch_table = NULL;
|
||||||
|
static ebpf_extension_provider_t* _ebpf_global_helper_function_provider_context = NULL;
|
||||||
|
|
||||||
static ebpf_pinning_table_t* _ebpf_core_map_pinning_table = NULL;
|
static ebpf_pinning_table_t* _ebpf_core_map_pinning_table = NULL;
|
||||||
|
|
||||||
static ebpf_lock_t _ebpf_core_hook_table_lock = {0};
|
static ebpf_lock_t _ebpf_core_hook_table_lock = {0};
|
||||||
|
@ -35,18 +44,6 @@ static const void* _ebpf_program_helpers[] = {
|
||||||
(void*)&_ebpf_core_map_update_element,
|
(void*)&_ebpf_core_map_update_element,
|
||||||
(void*)&_ebpf_core_map_delete_element};
|
(void*)&_ebpf_core_map_delete_element};
|
||||||
|
|
||||||
size_t
|
|
||||||
ebpf_core_get_global_helper_count()
|
|
||||||
{
|
|
||||||
return EBPF_COUNT_OF(_ebpf_program_helpers);
|
|
||||||
}
|
|
||||||
|
|
||||||
const void*
|
|
||||||
ebpf_core_get_global_helper(size_t helper_id)
|
|
||||||
{
|
|
||||||
return _ebpf_program_helpers[helper_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
static ebpf_error_code_t
|
static ebpf_error_code_t
|
||||||
_ebpf_core_set_hook_entry(ebpf_program_t* code, ebpf_program_type_t program_type)
|
_ebpf_core_set_hook_entry(ebpf_program_t* code, ebpf_program_type_t program_type)
|
||||||
{
|
{
|
||||||
|
@ -101,13 +98,38 @@ ebpf_core_initiate()
|
||||||
|
|
||||||
ebpf_lock_create(&_ebpf_core_hook_table_lock);
|
ebpf_lock_create(&_ebpf_core_hook_table_lock);
|
||||||
|
|
||||||
|
_ebpf_global_helper_function_dispatch_table = ebpf_allocate(
|
||||||
|
EBPF_OFFSET_OF(ebpf_extension_dispatch_table_t, function) + sizeof(_ebpf_program_helpers),
|
||||||
|
EBPF_MEMORY_NO_EXECUTE);
|
||||||
|
if (!_ebpf_global_helper_function_dispatch_table) {
|
||||||
|
return_value = EBPF_ERROR_OUT_OF_RESOURCES;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ebpf_global_helper_function_dispatch_table->version = 0;
|
||||||
|
_ebpf_global_helper_function_dispatch_table->size =
|
||||||
|
EBPF_OFFSET_OF(ebpf_extension_dispatch_table_t, function) + sizeof(_ebpf_program_helpers);
|
||||||
|
|
||||||
|
memcpy(_ebpf_global_helper_function_dispatch_table->function, _ebpf_program_helpers, sizeof(_ebpf_program_helpers));
|
||||||
|
|
||||||
|
return_value = ebpf_provider_load(
|
||||||
|
&_ebpf_global_helper_function_provider_context,
|
||||||
|
&ebpf_global_helper_function_interface_id,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
_ebpf_global_helper_function_dispatch_table,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
return_value = ebpf_get_code_integrity_state(&_ebpf_core_code_integrity_state);
|
return_value = ebpf_get_code_integrity_state(&_ebpf_core_code_integrity_state);
|
||||||
|
|
||||||
Done:
|
Done:
|
||||||
if (return_value != EBPF_ERROR_SUCCESS) {
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
ebpf_epoch_terminate();
|
ebpf_core_terminate();
|
||||||
ebpf_platform_terminate();
|
|
||||||
ebpf_handle_table_terminate();
|
|
||||||
}
|
}
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
@ -115,6 +137,12 @@ Done:
|
||||||
void
|
void
|
||||||
ebpf_core_terminate()
|
ebpf_core_terminate()
|
||||||
{
|
{
|
||||||
|
epbf_provider_unload(_ebpf_global_helper_function_provider_context);
|
||||||
|
_ebpf_global_helper_function_provider_context = NULL;
|
||||||
|
|
||||||
|
ebpf_free(_ebpf_global_helper_function_dispatch_table);
|
||||||
|
_ebpf_global_helper_function_dispatch_table = NULL;
|
||||||
|
|
||||||
ebpf_handle_table_terminate();
|
ebpf_handle_table_terminate();
|
||||||
|
|
||||||
ebpf_pinning_table_free(_ebpf_core_map_pinning_table);
|
ebpf_pinning_table_free(_ebpf_core_map_pinning_table);
|
||||||
|
|
|
@ -17,17 +17,14 @@ typedef struct _ebpf_hook_instance
|
||||||
ebpf_program_entry_point_t program_entry_point;
|
ebpf_program_entry_point_t program_entry_point;
|
||||||
|
|
||||||
ebpf_attach_type_t attach_type;
|
ebpf_attach_type_t attach_type;
|
||||||
|
ebpf_extension_data_t* client_data;
|
||||||
ebpf_extension_client_t* extension_client_context;
|
ebpf_extension_client_t* extension_client_context;
|
||||||
|
|
||||||
uint8_t* hook_properties;
|
void* provider_binding_context;
|
||||||
size_t hook_properties_length;
|
ebpf_extension_data_t* provider_data;
|
||||||
|
|
||||||
ebpf_extension_dispatch_table_t* provider_dispatch_table;
|
ebpf_extension_dispatch_table_t* provider_dispatch_table;
|
||||||
} ebpf_hook_instance_t;
|
} ebpf_hook_instance_t;
|
||||||
|
|
||||||
// TODO: Get the actual GUID for the hook client.
|
|
||||||
static const GUID _ebpf_hook_client_id = {0};
|
|
||||||
|
|
||||||
ebpf_error_code_t
|
ebpf_error_code_t
|
||||||
_ebpf_hook_instance_invoke(const ebpf_hook_instance_t* hook, void* program_context);
|
_ebpf_hook_instance_invoke(const ebpf_hook_instance_t* hook, void* program_context);
|
||||||
|
|
||||||
|
@ -43,6 +40,7 @@ _ebpf_hook_free(ebpf_object_t* object)
|
||||||
ebpf_hook_instance_t* hook = (ebpf_hook_instance_t*)object;
|
ebpf_hook_instance_t* hook = (ebpf_hook_instance_t*)object;
|
||||||
ebpf_hook_instance_detach_program(hook);
|
ebpf_hook_instance_detach_program(hook);
|
||||||
ebpf_extension_unload(hook->extension_client_context);
|
ebpf_extension_unload(hook->extension_client_context);
|
||||||
|
ebpf_free(hook->client_data);
|
||||||
ebpf_epoch_free(hook);
|
ebpf_epoch_free(hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,16 +62,26 @@ ebpf_hook_instance_initialize(
|
||||||
ebpf_hook_instance_t* hook, ebpf_attach_type_t attach_type, const uint8_t* context_data, size_t context_data_length)
|
ebpf_hook_instance_t* hook, ebpf_attach_type_t attach_type, const uint8_t* context_data, size_t context_data_length)
|
||||||
{
|
{
|
||||||
ebpf_error_code_t return_value;
|
ebpf_error_code_t return_value;
|
||||||
|
size_t client_data_length;
|
||||||
|
|
||||||
|
ebpf_safe_size_t_add(sizeof(ebpf_extension_data_t), context_data_length, &client_data_length);
|
||||||
|
|
||||||
|
hook->client_data = ebpf_allocate(client_data_length, EBPF_MEMORY_NO_EXECUTE);
|
||||||
|
if (!hook->client_data)
|
||||||
|
return EBPF_ERROR_OUT_OF_RESOURCES;
|
||||||
|
|
||||||
|
hook->client_data->version = 0;
|
||||||
|
hook->client_data->size = (uint16_t)client_data_length;
|
||||||
|
memcpy(hook->client_data->data, context_data, context_data_length);
|
||||||
|
|
||||||
return_value = ebpf_extension_load(
|
return_value = ebpf_extension_load(
|
||||||
&(hook->extension_client_context),
|
&(hook->extension_client_context),
|
||||||
&_ebpf_hook_client_id,
|
|
||||||
context_data,
|
|
||||||
context_data_length,
|
|
||||||
(ebpf_extension_dispatch_table_t*)&_ebpf_hook_dispatch_table,
|
|
||||||
&attach_type,
|
&attach_type,
|
||||||
&(hook->hook_properties),
|
hook,
|
||||||
&(hook->hook_properties_length),
|
hook->client_data,
|
||||||
|
(ebpf_extension_dispatch_table_t*)&_ebpf_hook_dispatch_table,
|
||||||
|
&(hook->provider_binding_context),
|
||||||
|
&(hook->provider_data),
|
||||||
&(hook->provider_dispatch_table));
|
&(hook->provider_dispatch_table));
|
||||||
|
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -82,11 +90,11 @@ ebpf_hook_instance_initialize(
|
||||||
ebpf_error_code_t
|
ebpf_error_code_t
|
||||||
ebpf_hook_instance_get_properties(ebpf_hook_instance_t* hook, uint8_t** hook_properties, size_t* hook_properties_length)
|
ebpf_hook_instance_get_properties(ebpf_hook_instance_t* hook, uint8_t** hook_properties, size_t* hook_properties_length)
|
||||||
{
|
{
|
||||||
if (!hook->hook_properties)
|
if (!hook->provider_data)
|
||||||
return EBPF_ERROR_INVALID_PARAMETER;
|
return EBPF_ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
*hook_properties = hook->hook_properties;
|
*hook_properties = hook->provider_data->data;
|
||||||
*hook_properties_length = hook->hook_properties_length;
|
*hook_properties_length = hook->provider_data->size;
|
||||||
return EBPF_ERROR_SUCCESS;
|
return EBPF_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,11 @@ typedef struct _ebpf_program
|
||||||
// EBPF_CODE_EBPF
|
// EBPF_CODE_EBPF
|
||||||
struct ubpf_vm* vm;
|
struct ubpf_vm* vm;
|
||||||
} code_or_vm;
|
} code_or_vm;
|
||||||
|
|
||||||
|
ebpf_extension_client_t* global_helper_extension_client;
|
||||||
|
ebpf_extension_data_t* global_helper_provider_data;
|
||||||
|
ebpf_extension_dispatch_table_t* global_helper_provider_dispatch_table;
|
||||||
|
|
||||||
} ebpf_program_t;
|
} ebpf_program_t;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -35,6 +40,10 @@ _ebpf_program_free(ebpf_object_t* object)
|
||||||
if (!program)
|
if (!program)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (program->global_helper_extension_client) {
|
||||||
|
ebpf_extension_unload(program->global_helper_extension_client);
|
||||||
|
}
|
||||||
|
|
||||||
if (program->parameters.code_type == EBPF_CODE_NATIVE) {
|
if (program->parameters.code_type == EBPF_CODE_NATIVE) {
|
||||||
ebpf_epoch_free(program->code_or_vm.code);
|
ebpf_epoch_free(program->code_or_vm.code);
|
||||||
} else {
|
} else {
|
||||||
|
@ -66,6 +75,20 @@ ebpf_program_initialize(ebpf_program_t* program, const ebpf_program_parameters_t
|
||||||
ebpf_error_code_t return_value;
|
ebpf_error_code_t return_value;
|
||||||
ebpf_utf8_string_t local_program_name = {NULL, 0};
|
ebpf_utf8_string_t local_program_name = {NULL, 0};
|
||||||
ebpf_utf8_string_t local_section_name = {NULL, 0};
|
ebpf_utf8_string_t local_section_name = {NULL, 0};
|
||||||
|
void* provider_binding_context;
|
||||||
|
|
||||||
|
return_value = ebpf_extension_load(
|
||||||
|
&program->global_helper_extension_client,
|
||||||
|
&ebpf_global_helper_function_interface_id,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&provider_binding_context,
|
||||||
|
&program->global_helper_provider_data,
|
||||||
|
&program->global_helper_provider_dispatch_table);
|
||||||
|
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
return_value = ebpf_duplicate_utf8_string(&local_program_name, &program_parameters->program_name);
|
return_value = ebpf_duplicate_utf8_string(&local_program_name, &program_parameters->program_name);
|
||||||
if (return_value != EBPF_ERROR_SUCCESS)
|
if (return_value != EBPF_ERROR_SUCCESS)
|
||||||
|
@ -127,17 +150,19 @@ Done:
|
||||||
}
|
}
|
||||||
|
|
||||||
static ebpf_error_code_t
|
static ebpf_error_code_t
|
||||||
_ebpf_program_register_helpers(struct ubpf_vm* vm)
|
_ebpf_program_register_helpers(ebpf_program_t* program)
|
||||||
{
|
{
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
size_t count = ebpf_core_get_global_helper_count();
|
size_t count = (program->global_helper_provider_dispatch_table->size -
|
||||||
|
EBPF_OFFSET_OF(ebpf_extension_dispatch_table_t, function)) /
|
||||||
|
sizeof(program->global_helper_provider_dispatch_table->function);
|
||||||
|
|
||||||
for (index = 0; index < count; index++) {
|
for (index = 0; index < count; index++) {
|
||||||
const void* helper = ebpf_core_get_global_helper(index);
|
const void* helper = (void*)program->global_helper_provider_dispatch_table->function[index];
|
||||||
if (helper == NULL)
|
if (helper == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ubpf_register(vm, (unsigned int)index, NULL, (void*)helper) < 0)
|
if (ubpf_register(program->code_or_vm.vm, (unsigned int)index, NULL, (void*)helper) < 0)
|
||||||
return EBPF_ERROR_INVALID_PARAMETER;
|
return EBPF_ERROR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
return EBPF_ERROR_SUCCESS;
|
return EBPF_ERROR_SUCCESS;
|
||||||
|
@ -160,7 +185,7 @@ ebpf_program_load_byte_code(ebpf_program_t* program, ebpf_instuction_t* instruct
|
||||||
// failing.
|
// failing.
|
||||||
toggle_bounds_check(program->code_or_vm.vm, false);
|
toggle_bounds_check(program->code_or_vm.vm, false);
|
||||||
|
|
||||||
return_value = _ebpf_program_register_helpers(program->code_or_vm.vm);
|
return_value = _ebpf_program_register_helpers(program);
|
||||||
if (return_value != EBPF_ERROR_SUCCESS)
|
if (return_value != EBPF_ERROR_SUCCESS)
|
||||||
goto Done;
|
goto Done;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,343 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Microsoft Corporation
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include "ebpf_platform.h"
|
||||||
|
|
||||||
|
typedef struct _ebpf_extension_client
|
||||||
|
{
|
||||||
|
NPIID npi_id;
|
||||||
|
NPI_CLIENT_CHARACTERISTICS client_characteristics;
|
||||||
|
NPI_MODULEID client_id;
|
||||||
|
void* client_binding_context;
|
||||||
|
const ebpf_extension_data_t* client_data;
|
||||||
|
const ebpf_extension_dispatch_table_t* client_dispatch_table;
|
||||||
|
NPI_MODULEID provider_id;
|
||||||
|
void* provider_binding_context;
|
||||||
|
ebpf_extension_data_t* provider_data;
|
||||||
|
ebpf_extension_dispatch_table_t* provider_dispatch_table;
|
||||||
|
HANDLE nmr_client_handle;
|
||||||
|
bool provider_is_attached;
|
||||||
|
} ebpf_extension_client_t;
|
||||||
|
|
||||||
|
typedef struct _ebpf_extension_provider
|
||||||
|
{
|
||||||
|
NPIID npi_id;
|
||||||
|
NPI_PROVIDER_CHARACTERISTICS provider_characteristics;
|
||||||
|
NPI_MODULEID provider_id;
|
||||||
|
void* provider_binding_context;
|
||||||
|
const ebpf_extension_data_t* provider_data;
|
||||||
|
const ebpf_extension_dispatch_table_t* provider_dispatch_table;
|
||||||
|
HANDLE nmr_provider_handle;
|
||||||
|
ebpf_provider_client_attach_callback_t client_attach_callback;
|
||||||
|
ebpf_provider_client_detach_callback_t client_detach_callback;
|
||||||
|
} ebpf_extension_provider_t;
|
||||||
|
|
||||||
|
typedef struct _ebpf_extension_provider_binding_context
|
||||||
|
{
|
||||||
|
GUID client_id;
|
||||||
|
ebpf_provider_client_detach_callback_t client_detach_callback;
|
||||||
|
} ebpf_extension_provider_binding_context;
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
_ebpf_extension_client_attach_provider(
|
||||||
|
HANDLE nmr_binding_handle, void* client_context, const NPI_REGISTRATION_INSTANCE* provider_registration_instance)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
ebpf_extension_client_t* local_client_context = (ebpf_extension_client_t*)client_context;
|
||||||
|
|
||||||
|
// Only permit one provider to attach.
|
||||||
|
if (local_client_context->provider_data != NULL) {
|
||||||
|
return STATUS_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the interface matches.
|
||||||
|
if (memcmp(
|
||||||
|
provider_registration_instance->NpiId,
|
||||||
|
&local_client_context->npi_id,
|
||||||
|
sizeof(local_client_context->npi_id)) != 0) {
|
||||||
|
return STATUS_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_client_context->provider_id = *provider_registration_instance->ModuleId;
|
||||||
|
local_client_context->provider_data =
|
||||||
|
(ebpf_extension_data_t*)provider_registration_instance->NpiSpecificCharacteristics;
|
||||||
|
|
||||||
|
status = NmrClientAttachProvider(
|
||||||
|
nmr_binding_handle,
|
||||||
|
local_client_context->client_binding_context,
|
||||||
|
local_client_context->client_dispatch_table,
|
||||||
|
&local_client_context->provider_binding_context,
|
||||||
|
&local_client_context->provider_dispatch_table);
|
||||||
|
|
||||||
|
local_client_context->provider_is_attached = NT_SUCCESS(status);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
_ebpf_extension_client_detach_provider(void* client_binding_context)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(client_binding_context);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ebpf_extension_client_cleanup_binding_context(void* client_binding_context)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(client_binding_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ebpf_error_code_t
|
||||||
|
ebpf_extension_load(
|
||||||
|
ebpf_extension_client_t** client_context,
|
||||||
|
const GUID* interface_id,
|
||||||
|
void* client_binding_context,
|
||||||
|
const ebpf_extension_data_t* client_data,
|
||||||
|
const ebpf_extension_dispatch_table_t* client_dispatch_table,
|
||||||
|
void** provider_binding_context,
|
||||||
|
ebpf_extension_data_t** provider_data,
|
||||||
|
ebpf_extension_dispatch_table_t** provider_dispatch_table)
|
||||||
|
{
|
||||||
|
ebpf_error_code_t return_value;
|
||||||
|
ebpf_extension_client_t* local_client_context;
|
||||||
|
NPI_CLIENT_CHARACTERISTICS* client_characteristics;
|
||||||
|
NPI_REGISTRATION_INSTANCE* client_registration_instance;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
local_client_context = ebpf_allocate(sizeof(ebpf_extension_client_t), EBPF_MEMORY_NO_EXECUTE);
|
||||||
|
|
||||||
|
if (!local_client_context) {
|
||||||
|
return_value = EBPF_ERROR_OUT_OF_RESOURCES;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(local_client_context, 0, sizeof(ebpf_extension_client_t));
|
||||||
|
|
||||||
|
local_client_context->client_data = client_data;
|
||||||
|
local_client_context->npi_id = *interface_id;
|
||||||
|
local_client_context->client_binding_context = client_binding_context;
|
||||||
|
local_client_context->client_id.Length = sizeof(local_client_context->client_id);
|
||||||
|
local_client_context->client_id.Type = MIT_GUID;
|
||||||
|
local_client_context->client_dispatch_table = client_dispatch_table;
|
||||||
|
|
||||||
|
status = ExUuidCreate(&local_client_context->client_id.Guid);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
return_value = EBPF_ERROR_EXTENSION_FAILED_TO_LOAD;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_characteristics = &(local_client_context->client_characteristics);
|
||||||
|
client_registration_instance = &(client_characteristics->ClientRegistrationInstance);
|
||||||
|
|
||||||
|
client_characteristics->Version = 0;
|
||||||
|
client_characteristics->Length = sizeof(*client_characteristics);
|
||||||
|
client_characteristics->ClientAttachProvider = _ebpf_extension_client_attach_provider;
|
||||||
|
client_characteristics->ClientDetachProvider = _ebpf_extension_client_detach_provider;
|
||||||
|
client_characteristics->ClientCleanupBindingContext = _ebpf_extension_client_cleanup_binding_context;
|
||||||
|
|
||||||
|
client_registration_instance->Version = 0;
|
||||||
|
client_registration_instance->Size = sizeof(*client_registration_instance);
|
||||||
|
client_registration_instance->NpiId = &local_client_context->npi_id;
|
||||||
|
client_registration_instance->ModuleId = &local_client_context->client_id;
|
||||||
|
|
||||||
|
client_registration_instance->NpiSpecificCharacteristics = &local_client_context->client_data;
|
||||||
|
|
||||||
|
status = NmrRegisterClient(client_characteristics, local_client_context, &local_client_context->nmr_client_handle);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
return_value = EBPF_ERROR_EXTENSION_FAILED_TO_LOAD;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!local_client_context->provider_is_attached) {
|
||||||
|
return_value = EBPF_ERROR_EXTENSION_FAILED_TO_LOAD;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*provider_binding_context = local_client_context->provider_binding_context;
|
||||||
|
*provider_data = local_client_context->provider_data;
|
||||||
|
*provider_dispatch_table = local_client_context->provider_dispatch_table;
|
||||||
|
*client_context = local_client_context;
|
||||||
|
local_client_context = NULL;
|
||||||
|
return_value = EBPF_ERROR_SUCCESS;
|
||||||
|
|
||||||
|
Done:
|
||||||
|
ebpf_free(local_client_context);
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ebpf_extension_unload(ebpf_extension_client_t* client_context)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
if (client_context) {
|
||||||
|
status = NmrDeregisterClient(client_context->nmr_client_handle);
|
||||||
|
if (status == STATUS_PENDING)
|
||||||
|
NmrWaitForClientDeregisterComplete(client_context->nmr_client_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ebpf_free(client_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
_ebpf_extension_provider_attach_client(
|
||||||
|
HANDLE nmr_binding_handle,
|
||||||
|
PVOID provider_context,
|
||||||
|
const NPI_REGISTRATION_INSTANCE* client_registration_instance,
|
||||||
|
void* client_binding_context,
|
||||||
|
const void* client_dispatch,
|
||||||
|
void** provider_binding_context,
|
||||||
|
const void** provider_dispatch)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
ebpf_error_code_t return_value;
|
||||||
|
ebpf_extension_provider_t* local_provider_context = (ebpf_extension_provider_t*)provider_context;
|
||||||
|
ebpf_extension_provider_binding_context* local_provider_binding_context = NULL;
|
||||||
|
UNREFERENCED_PARAMETER(nmr_binding_handle);
|
||||||
|
UNREFERENCED_PARAMETER(client_binding_context);
|
||||||
|
|
||||||
|
// Check that the interface matches.
|
||||||
|
if (memcmp(
|
||||||
|
client_registration_instance->NpiId,
|
||||||
|
&local_provider_context->npi_id,
|
||||||
|
sizeof(local_provider_context->npi_id)) != 0) {
|
||||||
|
status = STATUS_NOINTERFACE;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_provider_binding_context = (ebpf_extension_provider_binding_context*)ebpf_allocate(
|
||||||
|
sizeof(ebpf_extension_provider_binding_context), EBPF_MEMORY_NO_EXECUTE);
|
||||||
|
|
||||||
|
if (!local_provider_binding_context) {
|
||||||
|
status = STATUS_NOINTERFACE;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_provider_binding_context->client_id = client_registration_instance->ModuleId->Guid;
|
||||||
|
local_provider_binding_context->client_detach_callback = local_provider_context->client_detach_callback;
|
||||||
|
|
||||||
|
if (local_provider_context->client_attach_callback) {
|
||||||
|
return_value = local_provider_context->client_attach_callback(
|
||||||
|
client_binding_context,
|
||||||
|
&local_provider_binding_context->client_id,
|
||||||
|
(const ebpf_extension_data_t*)client_registration_instance->NpiSpecificCharacteristics,
|
||||||
|
(const ebpf_extension_dispatch_table_t*)client_dispatch);
|
||||||
|
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
|
status = STATUS_NOINTERFACE;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*provider_binding_context = local_provider_binding_context;
|
||||||
|
local_provider_binding_context = NULL;
|
||||||
|
*provider_dispatch = local_provider_context->provider_dispatch_table;
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
Done:
|
||||||
|
ebpf_free(local_provider_binding_context);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
_ebpf_extension_provider_detach_client(void* provider_binding_context)
|
||||||
|
{
|
||||||
|
ebpf_extension_provider_binding_context* local_provider_binding_context =
|
||||||
|
(ebpf_extension_provider_binding_context*)provider_binding_context;
|
||||||
|
|
||||||
|
if (local_provider_binding_context->client_detach_callback)
|
||||||
|
local_provider_binding_context->client_detach_callback(&local_provider_binding_context->client_id);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_ebpf_extension_provider_cleanup_binding_context(void* provider_binding_context)
|
||||||
|
{
|
||||||
|
ebpf_free(provider_binding_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ebpf_error_code_t
|
||||||
|
ebpf_provider_load(
|
||||||
|
ebpf_extension_provider_t** provider_context,
|
||||||
|
const GUID* interface_id,
|
||||||
|
void* provider_binding_context,
|
||||||
|
const ebpf_extension_data_t* provider_data,
|
||||||
|
const ebpf_extension_dispatch_table_t* provider_dispatch_table,
|
||||||
|
ebpf_provider_client_attach_callback_t client_attach_callback,
|
||||||
|
ebpf_provider_client_detach_callback_t client_detach_callback)
|
||||||
|
{
|
||||||
|
ebpf_error_code_t return_value;
|
||||||
|
ebpf_extension_provider_t* local_provider_context;
|
||||||
|
NPI_PROVIDER_CHARACTERISTICS* provider_characteristics;
|
||||||
|
NPI_REGISTRATION_INSTANCE* provider_registration_instance;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
local_provider_context = ebpf_allocate(sizeof(ebpf_extension_provider_t), EBPF_MEMORY_NO_EXECUTE);
|
||||||
|
|
||||||
|
if (!local_provider_context) {
|
||||||
|
return_value = EBPF_ERROR_OUT_OF_RESOURCES;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(local_provider_context, 0, sizeof(ebpf_extension_client_t));
|
||||||
|
|
||||||
|
local_provider_context->provider_binding_context = provider_binding_context;
|
||||||
|
local_provider_context->provider_data = provider_data;
|
||||||
|
local_provider_context->npi_id = *interface_id;
|
||||||
|
local_provider_context->provider_id.Length = sizeof(local_provider_context->provider_id);
|
||||||
|
local_provider_context->provider_id.Type = MIT_GUID;
|
||||||
|
local_provider_context->provider_dispatch_table = provider_dispatch_table;
|
||||||
|
local_provider_context->client_attach_callback = client_attach_callback;
|
||||||
|
local_provider_context->client_detach_callback = client_detach_callback;
|
||||||
|
|
||||||
|
status = ExUuidCreate(&local_provider_context->provider_id.Guid);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
return_value = EBPF_ERROR_EXTENSION_FAILED_TO_LOAD;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
provider_characteristics = &(local_provider_context->provider_characteristics);
|
||||||
|
provider_registration_instance = &(provider_characteristics->ProviderRegistrationInstance);
|
||||||
|
|
||||||
|
provider_characteristics->Version = 0;
|
||||||
|
provider_characteristics->Length = sizeof(*provider_characteristics);
|
||||||
|
provider_characteristics->ProviderAttachClient = _ebpf_extension_provider_attach_client;
|
||||||
|
provider_characteristics->ProviderDetachClient = _ebpf_extension_provider_detach_client;
|
||||||
|
provider_characteristics->ProviderCleanupBindingContext = _ebpf_extension_provider_cleanup_binding_context;
|
||||||
|
|
||||||
|
provider_registration_instance->Version = 0;
|
||||||
|
provider_registration_instance->Size = sizeof(*provider_registration_instance);
|
||||||
|
provider_registration_instance->NpiId = &local_provider_context->npi_id;
|
||||||
|
provider_registration_instance->ModuleId = &local_provider_context->provider_id;
|
||||||
|
|
||||||
|
provider_registration_instance->NpiSpecificCharacteristics = &local_provider_context->provider_data;
|
||||||
|
|
||||||
|
status = NmrRegisterProvider(
|
||||||
|
provider_characteristics, local_provider_context, &local_provider_context->nmr_provider_handle);
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
return_value = EBPF_ERROR_EXTENSION_FAILED_TO_LOAD;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*provider_context = local_provider_context;
|
||||||
|
local_provider_context = NULL;
|
||||||
|
return_value = EBPF_ERROR_SUCCESS;
|
||||||
|
|
||||||
|
Done:
|
||||||
|
ebpf_free(local_provider_context);
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
epbf_provider_unload(ebpf_extension_provider_t* provider_context)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
if (provider_context) {
|
||||||
|
status = NmrDeregisterProvider(provider_context->nmr_provider_handle);
|
||||||
|
if (status == STATUS_PENDING)
|
||||||
|
NmrWaitForProviderDeregisterComplete(provider_context->nmr_provider_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ebpf_free(provider_context);
|
||||||
|
}
|
|
@ -43,7 +43,8 @@
|
||||||
<ClCompile Include="..\ebpf_hash_table.c" />
|
<ClCompile Include="..\ebpf_hash_table.c" />
|
||||||
<ClCompile Include="..\ebpf_object.c" />
|
<ClCompile Include="..\ebpf_object.c" />
|
||||||
<ClCompile Include="..\ebpf_pinning_table.c" />
|
<ClCompile Include="..\ebpf_pinning_table.c" />
|
||||||
<ClCompile Include="platform_kernel.c" />
|
<ClCompile Include="ebpf_extension_kernel.c" />
|
||||||
|
<ClCompile Include="ebpf_platform_kernel.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\include\ebpf_platform.h" />
|
<ClInclude Include="..\..\..\include\ebpf_platform.h" />
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="platform_kernel.c">
|
<ClCompile Include="ebpf_platform_kernel.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\ebpf_hash_table.c">
|
<ClCompile Include="..\ebpf_hash_table.c">
|
||||||
|
@ -34,6 +34,9 @@
|
||||||
<ClCompile Include="..\ebpf_handle.c">
|
<ClCompile Include="..\ebpf_handle.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="ebpf_extension_kernel.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\include\ebpf_platform.h">
|
<ClInclude Include="..\..\..\include\ebpf_platform.h">
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) Microsoft Corporation
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include "ebpf_platform.h"
|
||||||
|
|
||||||
|
typedef struct _ebpf_extension_client
|
||||||
|
{
|
||||||
|
GUID client_id;
|
||||||
|
GUID interface_id;
|
||||||
|
void* client_binding_context;
|
||||||
|
const ebpf_extension_data_t* client_data;
|
||||||
|
const ebpf_extension_dispatch_table_t* client_dispatch_table;
|
||||||
|
} ebpf_extension_client_t;
|
||||||
|
|
||||||
|
typedef struct _ebpf_extension_provider
|
||||||
|
{
|
||||||
|
GUID interface_id;
|
||||||
|
void* provider_binding_context;
|
||||||
|
const ebpf_extension_data_t* provider_data;
|
||||||
|
const ebpf_extension_dispatch_table_t* provider_dispatch_table;
|
||||||
|
ebpf_provider_client_attach_callback_t client_attach_callback;
|
||||||
|
ebpf_provider_client_detach_callback_t client_detach_callback;
|
||||||
|
ebpf_hash_table_t* client_table;
|
||||||
|
} ebpf_extension_provider_t;
|
||||||
|
|
||||||
|
ebpf_lock_t _ebpf_provider_table_lock = {0};
|
||||||
|
ebpf_hash_table_t* _ebpf_provider_table = NULL;
|
||||||
|
|
||||||
|
ebpf_error_code_t
|
||||||
|
ebpf_extension_load(
|
||||||
|
ebpf_extension_client_t** client_context,
|
||||||
|
const GUID* interface_id,
|
||||||
|
void* client_binding_context,
|
||||||
|
const ebpf_extension_data_t* client_data,
|
||||||
|
const ebpf_extension_dispatch_table_t* client_dispatch_table,
|
||||||
|
void** provider_binding_context,
|
||||||
|
ebpf_extension_data_t** provider_data,
|
||||||
|
ebpf_extension_dispatch_table_t** provider_dispatch_table)
|
||||||
|
{
|
||||||
|
ebpf_error_code_t return_value;
|
||||||
|
ebpf_lock_state_t state;
|
||||||
|
ebpf_extension_provider_t* local_extension_provider = NULL;
|
||||||
|
ebpf_extension_provider_t** hash_table_find_result = NULL;
|
||||||
|
ebpf_extension_client_t* local_extension_client = NULL;
|
||||||
|
ebpf_lock_lock(&_ebpf_provider_table_lock, &state);
|
||||||
|
|
||||||
|
if (!_ebpf_provider_table) {
|
||||||
|
return_value = EBPF_ERROR_NOT_FOUND;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_extension_client = ebpf_allocate(sizeof(ebpf_extension_client_t), EBPF_MEMORY_NO_EXECUTE);
|
||||||
|
if (!local_extension_client) {
|
||||||
|
return_value = EBPF_ERROR_OUT_OF_RESOURCES;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(local_extension_client, 0, sizeof(ebpf_extension_client_t));
|
||||||
|
local_extension_client->client_binding_context = client_binding_context;
|
||||||
|
local_extension_client->client_data = client_data;
|
||||||
|
local_extension_client->client_dispatch_table = client_dispatch_table;
|
||||||
|
local_extension_client->interface_id = *interface_id;
|
||||||
|
|
||||||
|
ebpf_guid_create(&local_extension_client->client_id);
|
||||||
|
|
||||||
|
return_value =
|
||||||
|
ebpf_hash_table_find(_ebpf_provider_table, (const uint8_t*)interface_id, (uint8_t**)&hash_table_find_result);
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
|
return_value = EBPF_ERROR_NOT_FOUND;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
local_extension_provider = *hash_table_find_result;
|
||||||
|
|
||||||
|
return_value = ebpf_hash_table_update(
|
||||||
|
local_extension_provider->client_table,
|
||||||
|
(const uint8_t*)&local_extension_client->client_id,
|
||||||
|
(const uint8_t*)&local_extension_client);
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_extension_provider->client_attach_callback) {
|
||||||
|
return_value = local_extension_provider->client_attach_callback(
|
||||||
|
local_extension_client->client_binding_context,
|
||||||
|
&local_extension_client->client_id,
|
||||||
|
client_data,
|
||||||
|
client_dispatch_table);
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
|
return_value = EBPF_ERROR_NOT_FOUND;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*client_context = local_extension_client;
|
||||||
|
local_extension_client = NULL;
|
||||||
|
|
||||||
|
*provider_binding_context = local_extension_provider->provider_binding_context;
|
||||||
|
*provider_data = local_extension_provider->provider_data;
|
||||||
|
*provider_dispatch_table = local_extension_provider->provider_dispatch_table;
|
||||||
|
|
||||||
|
Done:
|
||||||
|
if (local_extension_provider && local_extension_client) {
|
||||||
|
ebpf_hash_table_delete(
|
||||||
|
local_extension_provider->client_table, (const uint8_t*)&local_extension_client->client_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ebpf_lock_unlock(&_ebpf_provider_table_lock, &state);
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ebpf_extension_unload(ebpf_extension_client_t* client_context)
|
||||||
|
{
|
||||||
|
ebpf_error_code_t return_value;
|
||||||
|
ebpf_lock_state_t state;
|
||||||
|
ebpf_extension_provider_t** hash_table_find_result = NULL;
|
||||||
|
ebpf_extension_provider_t* local_extension_provider = NULL;
|
||||||
|
|
||||||
|
if (client_context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ebpf_lock_lock(&_ebpf_provider_table_lock, &state);
|
||||||
|
|
||||||
|
if (!_ebpf_provider_table) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_value = ebpf_hash_table_find(
|
||||||
|
_ebpf_provider_table, (const uint8_t*)&client_context->interface_id, (uint8_t**)&hash_table_find_result);
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
local_extension_provider = *hash_table_find_result;
|
||||||
|
|
||||||
|
if (local_extension_provider->client_detach_callback) {
|
||||||
|
local_extension_provider->client_detach_callback(&client_context->client_id);
|
||||||
|
}
|
||||||
|
ebpf_hash_table_delete(local_extension_provider->client_table, (const uint8_t*)&client_context->client_id);
|
||||||
|
|
||||||
|
Done:
|
||||||
|
ebpf_free(client_context);
|
||||||
|
ebpf_lock_unlock(&_ebpf_provider_table_lock, &state);
|
||||||
|
}
|
||||||
|
|
||||||
|
ebpf_error_code_t
|
||||||
|
ebpf_provider_load(
|
||||||
|
ebpf_extension_provider_t** provider_context,
|
||||||
|
const GUID* interface_id,
|
||||||
|
void* provider_binding_context,
|
||||||
|
const ebpf_extension_data_t* provider_data,
|
||||||
|
const ebpf_extension_dispatch_table_t* provider_dispatch_table,
|
||||||
|
ebpf_provider_client_attach_callback_t client_attach_callback,
|
||||||
|
ebpf_provider_client_detach_callback_t client_detach_callback)
|
||||||
|
{
|
||||||
|
ebpf_error_code_t return_value;
|
||||||
|
ebpf_lock_state_t state;
|
||||||
|
ebpf_extension_provider_t* local_extension_provider = NULL;
|
||||||
|
ebpf_lock_lock(&_ebpf_provider_table_lock, &state);
|
||||||
|
|
||||||
|
if (!_ebpf_provider_table) {
|
||||||
|
return_value =
|
||||||
|
ebpf_hash_table_create(&_ebpf_provider_table, ebpf_allocate, ebpf_free, sizeof(GUID), sizeof(void*), NULL);
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS)
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_value =
|
||||||
|
ebpf_hash_table_find(_ebpf_provider_table, (const uint8_t*)interface_id, (uint8_t**)&local_extension_provider);
|
||||||
|
if (return_value == EBPF_ERROR_SUCCESS) {
|
||||||
|
return_value = EBPF_ERROR_DUPLICATE_NAME;
|
||||||
|
local_extension_provider = NULL;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_extension_provider = ebpf_allocate(sizeof(ebpf_extension_provider_t), EBPF_MEMORY_NO_EXECUTE);
|
||||||
|
if (!local_extension_provider) {
|
||||||
|
return_value = EBPF_ERROR_OUT_OF_RESOURCES;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
memset(local_extension_provider, 0, sizeof(ebpf_extension_provider_t));
|
||||||
|
|
||||||
|
local_extension_provider->interface_id = *interface_id;
|
||||||
|
local_extension_provider->provider_binding_context = provider_binding_context;
|
||||||
|
local_extension_provider->provider_data = provider_data;
|
||||||
|
local_extension_provider->provider_dispatch_table = provider_dispatch_table;
|
||||||
|
local_extension_provider->client_attach_callback = client_attach_callback;
|
||||||
|
local_extension_provider->client_detach_callback = client_detach_callback;
|
||||||
|
|
||||||
|
return_value = ebpf_hash_table_create(
|
||||||
|
&local_extension_provider->client_table, ebpf_allocate, ebpf_free, sizeof(GUID), sizeof(void*), NULL);
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_value = ebpf_hash_table_update(
|
||||||
|
_ebpf_provider_table, (const uint8_t*)interface_id, (const uint8_t*)&local_extension_provider);
|
||||||
|
if (return_value != EBPF_ERROR_SUCCESS)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
*provider_context = local_extension_provider;
|
||||||
|
local_extension_provider = NULL;
|
||||||
|
|
||||||
|
Done:
|
||||||
|
ebpf_lock_unlock(&_ebpf_provider_table_lock, &state);
|
||||||
|
ebpf_free(local_extension_provider);
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
epbf_provider_unload(ebpf_extension_provider_t* provider_context)
|
||||||
|
{
|
||||||
|
ebpf_error_code_t return_value;
|
||||||
|
ebpf_lock_state_t state;
|
||||||
|
ebpf_extension_provider_t* local_extension_provider = NULL;
|
||||||
|
GUID next_key;
|
||||||
|
|
||||||
|
if (!provider_context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ebpf_lock_lock(&_ebpf_provider_table_lock, &state);
|
||||||
|
|
||||||
|
if (!_ebpf_provider_table) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ebpf_hash_table_delete(_ebpf_provider_table, (const uint8_t*)&provider_context->interface_id);
|
||||||
|
|
||||||
|
return_value = ebpf_hash_table_next_key(_ebpf_provider_table, NULL, (uint8_t*)&next_key);
|
||||||
|
if (return_value == EBPF_ERROR_NO_MORE_KEYS) {
|
||||||
|
ebpf_hash_table_destroy(_ebpf_provider_table);
|
||||||
|
_ebpf_provider_table = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
ebpf_lock_unlock(&_ebpf_provider_table_lock, &state);
|
||||||
|
ebpf_free(local_extension_provider);
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
#include <intsafe.h>
|
#include <intsafe.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <random>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -327,3 +328,10 @@ ebpf_free_timer_work_item(ebpf_timer_work_item_t* work_item)
|
||||||
CloseThreadpoolTimer(work_item->threadpool_timer);
|
CloseThreadpoolTimer(work_item->threadpool_timer);
|
||||||
ebpf_free(work_item);
|
ebpf_free(work_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ebpf_error_code_t
|
||||||
|
ebpf_guid_create(GUID* new_guid)
|
||||||
|
{
|
||||||
|
UuidCreate(new_guid);
|
||||||
|
return EBPF_ERROR_SUCCESS;
|
||||||
|
}
|
|
@ -31,7 +31,8 @@
|
||||||
<ClCompile Include="..\ebpf_hash_table.c" />
|
<ClCompile Include="..\ebpf_hash_table.c" />
|
||||||
<ClCompile Include="..\ebpf_object.c" />
|
<ClCompile Include="..\ebpf_object.c" />
|
||||||
<ClCompile Include="..\ebpf_pinning_table.c" />
|
<ClCompile Include="..\ebpf_pinning_table.c" />
|
||||||
<ClCompile Include="platform_user.cpp" />
|
<ClCompile Include="ebpf_extension_user.c" />
|
||||||
|
<ClCompile Include="ebpf_platform_user.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<VCProjectVersion>16.0</VCProjectVersion>
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="platform_user.cpp">
|
<ClCompile Include="ebpf_platform_user.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\ebpf_pinning_table.c">
|
<ClCompile Include="..\ebpf_pinning_table.c">
|
||||||
|
@ -45,5 +45,8 @@
|
||||||
<ClCompile Include="..\ebpf_hash_table.c">
|
<ClCompile Include="..\ebpf_hash_table.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="ebpf_extension_user.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -97,7 +97,7 @@
|
||||||
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
||||||
</Midl>
|
</Midl>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib;$(DDK_LIB_PATH)\netio.lib;</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
<PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
|
||||||
</Midl>
|
</Midl>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib;execution_context_kernel.lib;ubpf_kernel.lib</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib;$(DDK_LIB_PATH)\netio.lib;execution_context_kernel.lib;ubpf_kernel.lib</AdditionalDependencies>
|
||||||
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>$(OutDir)</AdditionalLibraryDirectories>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
|
|
|
@ -740,4 +740,67 @@ TEST_CASE("epoch_test_two_threads", "[epoch_test_two_threads]")
|
||||||
std::thread thread_2(epoch);
|
std::thread thread_2(epoch);
|
||||||
thread_1.join();
|
thread_1.join();
|
||||||
thread_2.join();
|
thread_2.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("extension_test", "[extension_test]")
|
||||||
|
{
|
||||||
|
auto client_function = []() { return EBPF_ERROR_SUCCESS; };
|
||||||
|
auto provider_function = []() { return EBPF_ERROR_SUCCESS; };
|
||||||
|
auto provider_attach = [](const GUID* client_id,
|
||||||
|
void* client_binding_context,
|
||||||
|
const ebpf_extension_data_t* client_data,
|
||||||
|
const ebpf_extension_dispatch_table_t* client_dispatch_table) {
|
||||||
|
UNREFERENCED_PARAMETER(client_id);
|
||||||
|
UNREFERENCED_PARAMETER(client_data);
|
||||||
|
UNREFERENCED_PARAMETER(client_dispatch_table);
|
||||||
|
UNREFERENCED_PARAMETER(client_binding_context);
|
||||||
|
return EBPF_ERROR_SUCCESS;
|
||||||
|
};
|
||||||
|
auto provider_detach = [](const GUID* client_id) {
|
||||||
|
UNREFERENCED_PARAMETER(client_id);
|
||||||
|
return EBPF_ERROR_SUCCESS;
|
||||||
|
};
|
||||||
|
ebpf_extension_dispatch_table_t client_dispatch_table = {
|
||||||
|
0, sizeof(ebpf_extension_dispatch_table_t), client_function};
|
||||||
|
ebpf_extension_dispatch_table_t provider_dispatch_table = {
|
||||||
|
0, sizeof(ebpf_extension_dispatch_table_t), provider_function};
|
||||||
|
ebpf_extension_data_t client_data;
|
||||||
|
ebpf_extension_data_t provider_data;
|
||||||
|
GUID interface_id;
|
||||||
|
|
||||||
|
ebpf_extension_dispatch_table_t* returned_provider_dispatch_table;
|
||||||
|
ebpf_extension_data_t* returned_provider_data;
|
||||||
|
|
||||||
|
ebpf_extension_provider_t* provider_context;
|
||||||
|
ebpf_extension_client_t* client_context;
|
||||||
|
void* provider_binding_context;
|
||||||
|
|
||||||
|
ebpf_guid_create(&interface_id);
|
||||||
|
|
||||||
|
REQUIRE(
|
||||||
|
ebpf_provider_load(
|
||||||
|
&provider_context,
|
||||||
|
&interface_id,
|
||||||
|
nullptr,
|
||||||
|
&provider_data,
|
||||||
|
&provider_dispatch_table,
|
||||||
|
provider_attach,
|
||||||
|
provider_detach) == EBPF_ERROR_SUCCESS);
|
||||||
|
|
||||||
|
REQUIRE(
|
||||||
|
ebpf_extension_load(
|
||||||
|
&client_context,
|
||||||
|
&interface_id,
|
||||||
|
nullptr,
|
||||||
|
&client_data,
|
||||||
|
&client_dispatch_table,
|
||||||
|
&provider_binding_context,
|
||||||
|
&returned_provider_data,
|
||||||
|
&returned_provider_dispatch_table) == EBPF_ERROR_SUCCESS);
|
||||||
|
|
||||||
|
REQUIRE(returned_provider_data == &provider_data);
|
||||||
|
REQUIRE(returned_provider_dispatch_table == &provider_dispatch_table);
|
||||||
|
|
||||||
|
ebpf_extension_unload(client_context);
|
||||||
|
epbf_provider_unload(provider_context);
|
||||||
}
|
}
|
Загрузка…
Ссылка в новой задаче