program information serialization (#302)

* program information serialization.

Co-authored-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Shankar Seal 2021-06-28 16:47:34 -07:00 коммит произвёл GitHub
Родитель a0801d410c
Коммит a93f4ba714
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 924 добавлений и 343 удалений

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

@ -16,12 +16,15 @@ typedef unsigned long long uint64_t;
#endif
#include "../external/ebpf-verifier/src/ebpf_base.h"
#define EBPF_MAX_PROGRAM_DESCRIPTOR_NAME_LENGTH 256
#define EBPF_MAX_HELPER_FUNCTION_NAME_LENGTH 256
typedef struct _ebpf_program_type_descriptor
{
MIDL([string])
const char* name;
ebpf_context_descriptor_t* context_descriptor;
GUID platform_specific_data;
GUID program_type;
char is_privileged;
} ebpf_program_type_descriptor_t;
@ -39,4 +42,16 @@ typedef struct _ebpf_program_information
ebpf_program_type_descriptor_t program_type_descriptor;
uint32_t count_of_helpers;
MIDL([size_is(count_of_helpers)]) ebpf_helper_function_prototype_t* helper_prototype;
} ebpf_program_information_t;
} ebpf_program_information_t;
typedef struct _ebpf_helper_function_addresses
{
uint32_t helper_function_count;
MIDL([size_is(helper_function_count)]) uint64_t* helper_function_address;
} ebpf_helper_function_addresses_t;
typedef struct _ebpf_program_data
{
ebpf_program_information_t* program_information;
ebpf_helper_function_addresses_t* helper_function_addresses;
} ebpf_program_data_t;

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

@ -51,8 +51,9 @@ ebpf_get_program_byte_code(
_Out_ int* map_descriptors_count,
_Outptr_result_maybenull_ const char** error_message);
uint32_t
get_program_information_data(ebpf_program_type_t program_type, ebpf_extension_data_t** program_information_data);
ebpf_result_t
get_program_information_data(
ebpf_program_type_t program_type, _Outptr_ ebpf_program_information_t** program_information);
void
clean_up_ebpf_program(_In_ _Post_invalid_ ebpf_program_t* program);
@ -61,4 +62,4 @@ void
clean_up_ebpf_programs(_Inout_ std::vector<ebpf_program_t*>& programs);
void
clean_up_ebpf_maps(_Inout_ std::vector<ebpf_map_t*>& maps);
clean_up_ebpf_maps(_Inout_ std::vector<ebpf_map_t*>& maps);

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

@ -5,12 +5,14 @@
#include <stdexcept>
#include <vector>
#include <Windows.h>
#include "api_common.hpp"
#include "device_helper.hpp"
#include "ebpf_bind_program_data.h"
#include "ebpf_platform.h"
#include "ebpf_program_types.h"
#include "ebpf_protocol.h"
#include "ebpf_result.h"
#include "ebpf_serialize.h"
#include "ebpf_xdp_program_data.h"
#include "platform.h"
#include "platform.hpp"
@ -24,7 +26,19 @@ struct guid_compare
}
};
static thread_local std::map<GUID, ebpf_helper::ebpf_memory_ptr, guid_compare> _program_information_cache;
struct _ebpf_program_information_deleter
{
void
operator()(_In_ _Post_invalid_ ebpf_program_information_t* program_info)
{
ebpf_program_information_free(program_info);
}
};
typedef std::unique_ptr<ebpf_program_information_t, _ebpf_program_information_deleter> ebpf_program_information_ptr_t;
static thread_local std::map<GUID, ebpf_program_information_ptr_t, guid_compare> _program_information_cache;
static thread_local std::map<GUID, ebpf_helper::ebpf_memory_ptr, guid_compare> _static_program_information_cache;
void
clear_program_information_cache()
@ -32,36 +46,41 @@ clear_program_information_cache()
_program_information_cache.clear();
}
uint32_t
get_program_information_data(ebpf_program_type_t program_type, ebpf_extension_data_t** program_information_data)
ebpf_result_t
get_program_information_data(
ebpf_program_type_t program_type, _Outptr_ ebpf_program_information_t** program_information)
{
ebpf_protocol_buffer_t reply_buffer(1024);
size_t required_buffer_length;
ebpf_operation_get_program_information_request_t request{
sizeof(request), ebpf_operation_id_t::EBPF_OPERATION_GET_PROGRAM_INFORMATION, program_type};
*program_information = nullptr;
auto reply = reinterpret_cast<ebpf_operation_get_program_information_reply_t*>(reply_buffer.data());
uint32_t retval = invoke_ioctl(request, reply_buffer);
if (retval != ERROR_SUCCESS) {
return retval;
ebpf_result_t result = windows_error_to_ebpf_result(invoke_ioctl(request, reply_buffer));
if ((result != EBPF_SUCCESS) && (result != EBPF_INSUFFICIENT_BUFFER))
goto Exit;
if (result == EBPF_INSUFFICIENT_BUFFER) {
required_buffer_length = reply->header.length;
reply_buffer.resize(required_buffer_length);
reply = reinterpret_cast<ebpf_operation_get_program_information_reply_t*>(reply_buffer.data());
result = windows_error_to_ebpf_result(invoke_ioctl(request, reply_buffer));
if (result != EBPF_SUCCESS)
goto Exit;
}
if (reply->header.id != ebpf_operation_id_t::EBPF_OPERATION_GET_PROGRAM_INFORMATION) {
return ERROR_INVALID_PARAMETER;
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
size_t allocation_size =
reply->header.length - EBPF_OFFSET_OF(ebpf_operation_get_program_information_reply_t, version);
// Deserialize the reply data into program information.
result = ebpf_deserialize_program_information(reply->size, reply->data, program_information);
*program_information_data = (ebpf_extension_data_t*)malloc(allocation_size);
if (!*program_information_data)
return ERROR_OUTOFMEMORY;
memcpy(
*program_information_data,
reply_buffer.data() + EBPF_OFFSET_OF(ebpf_operation_get_program_information_reply_t, version),
allocation_size);
return retval;
Exit:
return result;
}
ebpf_result_t
@ -72,20 +91,26 @@ get_program_type_info(const ebpf_program_information_t** info)
ebpf_program_information_t* program_information;
const uint8_t* encoded_data = nullptr;
size_t encoded_data_size = 0;
bool fall_back = false;
// See if we already have the program information cached.
auto it = _program_information_cache.find(*program_type);
if (it == _program_information_cache.end()) {
// Try to query the information from the execution context.
ebpf_extension_data_t* program_information_data;
uint32_t error = get_program_information_data(*program_type, &program_information_data);
if (error == ERROR_SUCCESS) {
encoded_data = program_information_data->data;
encoded_data_size = program_information_data->size;
result = get_program_information_data(*program_type, &program_information);
if (result != EBPF_SUCCESS) {
fall_back = true;
} else {
// Fall back to using static data so that verification can be tried
// (e.g., from a netsh command) even if the execution context isn't running.
// TODO: remove this in the future.
_program_information_cache[*program_type] = ebpf_program_information_ptr_t(program_information);
}
}
if (fall_back) {
// Fall back to using static data so that verification can be tried
// (e.g., from a netsh command) even if the execution context isn't running.
// TODO: remove this in the future.
auto iter = _static_program_information_cache.find(*program_type);
if (iter == _static_program_information_cache.end()) {
if (memcmp(program_type, &EBPF_PROGRAM_TYPE_XDP, sizeof(*program_type)) == 0) {
encoded_data = _ebpf_encoded_xdp_program_information_data;
encoded_data_size = sizeof(_ebpf_encoded_xdp_program_information_data);
@ -93,20 +118,23 @@ get_program_type_info(const ebpf_program_information_t** info)
encoded_data = _ebpf_encoded_bind_program_information_data;
encoded_data_size = sizeof(_ebpf_encoded_bind_program_information_data);
}
}
if (encoded_data == nullptr) {
return EBPF_INVALID_ARGUMENT;
}
ebpf_assert(encoded_data != nullptr);
result = ebpf_program_information_decode(&program_information, encoded_data, (unsigned long)encoded_data_size);
if (result != EBPF_SUCCESS) {
return result;
}
result =
ebpf_program_information_decode(&program_information, encoded_data, (unsigned long)encoded_data_size);
if (result != EBPF_SUCCESS) {
return result;
}
_program_information_cache[*program_type] = ebpf_helper::ebpf_memory_ptr(program_information);
_static_program_information_cache[*program_type] = ebpf_helper::ebpf_memory_ptr(program_information);
}
}
*info = (const ebpf_program_information_t*)_program_information_cache[*program_type].get();
if (!fall_back) {
*info = (const ebpf_program_information_t*)_program_information_cache[*program_type].get();
} else {
*info = (const ebpf_program_information_t*)_static_program_information_cache[*program_type].get();
}
return EBPF_SUCCESS;
}

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

@ -84,7 +84,7 @@
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LinkIncremental>false</LinkIncremental>
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -135,6 +135,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>

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

@ -8,6 +8,7 @@
#include "ebpf_maps.h"
#include "ebpf_pinning_table.h"
#include "ebpf_program.h"
#include "ebpf_program_types.h"
#include "ebpf_serialize.h"
GUID ebpf_global_helper_function_interface_id = {/* 8d2a1d3f-9ce6-473d-b48e-17aa5c5581fe */
@ -16,9 +17,6 @@ GUID ebpf_global_helper_function_interface_id = {/* 8d2a1d3f-9ce6-473d-b48e-17aa
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;
// Assume enabled until we can query it.
@ -31,12 +29,25 @@ _ebpf_core_map_update_element(ebpf_map_t* map, const uint8_t* key, const uint8_t
static void
_ebpf_core_map_delete_element(ebpf_map_t* map, const uint8_t* key);
#define EBPF_CORE_GLOBAL_HELPER_EXTENSION_VERSION 0
static const void* _ebpf_program_helpers[] = {
NULL,
(void*)&_ebpf_core_map_find_element,
(void*)&_ebpf_core_map_update_element,
(void*)&_ebpf_core_map_delete_element};
static ebpf_extension_provider_t* _ebpf_global_helper_function_provider_context = NULL;
static ebpf_helper_function_addresses_t _ebpf_global_helper_function_dispatch_table = {
EBPF_COUNT_OF(_ebpf_program_helpers), (uint64_t*)_ebpf_program_helpers};
static ebpf_program_data_t _ebpf_global_helper_function_program_data = {NULL,
&_ebpf_global_helper_function_dispatch_table};
static ebpf_extension_data_t _ebpf_global_helper_function_extension_data = {
EBPF_CORE_GLOBAL_HELPER_EXTENSION_VERSION,
sizeof(_ebpf_global_helper_function_program_data),
&_ebpf_global_helper_function_program_data};
ebpf_result_t
ebpf_core_initiate()
{
@ -60,25 +71,12 @@ ebpf_core_initiate()
if (return_value != EBPF_SUCCESS)
goto Done;
_ebpf_global_helper_function_dispatch_table =
ebpf_allocate(EBPF_OFFSET_OF(ebpf_extension_dispatch_table_t, function) + sizeof(_ebpf_program_helpers));
if (!_ebpf_global_helper_function_dispatch_table) {
return_value = EBPF_NO_MEMORY;
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,
&_ebpf_global_helper_function_extension_data,
NULL,
_ebpf_global_helper_function_dispatch_table,
NULL,
NULL,
NULL);
@ -102,9 +100,6 @@ ebpf_core_terminate()
ebpf_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_pinning_table_free(_ebpf_core_map_pinning_table);
@ -683,9 +678,11 @@ _ebpf_core_protocol_get_program_information(
{
ebpf_result_t retval;
ebpf_program_t* program = NULL;
ebpf_extension_data_t* program_information_data;
size_t required_length;
ebpf_program_parameters_t program_parameters = {0};
ebpf_extension_data_t* program_information_data;
ebpf_program_data_t* program_data;
size_t serialization_buffer_size;
size_t required_length;
retval = ebpf_program_create(&program);
if (retval != EBPF_SUCCESS)
@ -700,21 +697,25 @@ _ebpf_core_protocol_get_program_information(
retval = ebpf_program_get_program_information_data(program, &program_information_data);
if (retval != EBPF_SUCCESS)
goto Done;
program_data = (ebpf_program_data_t*)program_information_data->data;
if (program_data->program_information == NULL) {
retval = EBPF_INVALID_ARGUMENT;
goto Done;
}
required_length = EBPF_OFFSET_OF(ebpf_operation_get_program_information_reply_t, data);
required_length += program_information_data->size;
serialization_buffer_size = reply_length - EBPF_OFFSET_OF(ebpf_operation_get_program_information_reply_t, data);
if (required_length > reply_length) {
retval = EBPF_INSUFFICIENT_BUFFER;
// Serialize program information structure onto reply data buffer.
retval = ebpf_serialize_program_information(
program_data->program_information, reply->data, serialization_buffer_size, &reply->size, &required_length);
if (retval != EBPF_SUCCESS) {
reply->header.length =
(uint16_t)(required_length + EBPF_OFFSET_OF(ebpf_operation_get_program_information_reply_t, data));
goto Done;
}
reply->version = program_information_data->version;
reply->size = program_information_data->size;
memcpy(&reply->data, program_information_data->data, program_information_data->size);
reply->header.length = (uint16_t)required_length;
retval = EBPF_SUCCESS;
Done:
ebpf_object_release_reference((ebpf_object_t*)program);
@ -786,12 +787,12 @@ _ebpf_core_protocol_serialize_map_information_reply(
serialization_buffer_size = output_buffer_length - EBPF_OFFSET_OF(ebpf_operation_get_map_information_reply_t, data);
result = ebpf_serialize_core_map_information_array(
result = ebpf_serialize_internal_map_information_array(
map_count,
map_info,
map_info_reply->data,
(const size_t)serialization_buffer_size,
(size_t*)&map_info_reply->size,
&map_info_reply->size,
&required_serialization_length);
if (result != EBPF_SUCCESS) {
@ -816,11 +817,6 @@ _ebpf_core_protocol_get_map_information(
UNREFERENCED_PARAMETER(request);
if (reply_length < (uint16_t)sizeof(ebpf_operation_get_map_information_reply_t)) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
// Enumerate all the pinning entries for map objects.
result = ebpf_pinning_table_enumerate_entries(
_ebpf_core_map_pinning_table, EBPF_OBJECT_MAP, &entry_count, &pinning_entries);
@ -840,6 +836,7 @@ _ebpf_core_protocol_get_map_information(
_Analysis_assume_(map_info != NULL);
// Serialize map information array onto reply structure.
_Analysis_assume_(map_info != NULL);
result = _ebpf_core_protocol_serialize_map_information_reply(entry_count, map_info, reply_length, reply);
Exit:

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

@ -18,7 +18,6 @@ typedef struct _ebpf_link
void* provider_binding_context;
ebpf_extension_data_t* provider_data;
ebpf_extension_dispatch_table_t* provider_dispatch_table;
} ebpf_link_t;
static ebpf_result_t
@ -78,7 +77,7 @@ ebpf_link_initialize(
(ebpf_extension_dispatch_table_t*)&_ebpf_link_dispatch_table,
&(link->provider_binding_context),
&(link->provider_data),
&(link->provider_dispatch_table),
NULL,
NULL);
return return_value;

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

@ -6,6 +6,7 @@
#include "ebpf_link.h"
#include "ebpf_object.h"
#include "ebpf_program.h"
#include "ebpf_program_types.h"
typedef struct _FILE FILE;
#include "ubpf.h"
@ -40,7 +41,7 @@ typedef struct _ebpf_program
ebpf_extension_client_t* program_information_client;
const void* program_information_binding_context;
const ebpf_extension_data_t* program_information_data;
const ebpf_extension_dispatch_table_t* program_information_provider_dispatch_table;
uint32_t helper_function_count;
bool program_invalidated;
ebpf_trampoline_table_t* trampoline_table;
@ -50,44 +51,53 @@ typedef struct _ebpf_program
static void
_ebpf_program_program_information_provider_changed(
void* client_binding_context,
const void* provider_binding_context,
const ebpf_extension_data_t* provider_data,
const ebpf_extension_dispatch_table_t* provider_dispatch_table)
_In_ void* client_binding_context,
_In_ const void* provider_binding_context,
_In_opt_ const ebpf_extension_data_t* provider_data)
{
ebpf_result_t return_value;
ebpf_program_t* program = (ebpf_program_t*)client_binding_context;
if (program->program_information_provider_dispatch_table != NULL) {
size_t function_count = (program->program_information_provider_dispatch_table->size -
EBPF_OFFSET_OF(ebpf_extension_dispatch_table_t, function)) /
sizeof(program->program_information_provider_dispatch_table->function[0]);
if (provider_data == NULL) {
// Extension is detaching. Program will get invalidated.
goto Exit;
} else {
ebpf_helper_function_addresses_t* helper_function_addresses = NULL;
if (provider_dispatch_table == NULL) {
program->program_invalidated = true;
return;
ebpf_program_data_t* program_data = (ebpf_program_data_t*)provider_data->data;
if (program_data == NULL) {
// An extension cannot have empty program_data.
goto Exit;
}
if (!program->trampoline_table) {
return_value = ebpf_allocate_trampoline_table(function_count, &program->trampoline_table);
if (return_value != EBPF_SUCCESS) {
program->program_invalidated = true;
return;
helper_function_addresses = program_data->helper_function_addresses;
if ((program->helper_function_count > 0) &&
(helper_function_addresses->helper_function_count != program->helper_function_count))
// A program information provider cannot modify helper function count upon reload.
goto Exit;
if (helper_function_addresses != NULL) {
if (!program->trampoline_table) {
// Program information provider is being loaded for the first time. Allocate trampoline table.
program->helper_function_count = helper_function_addresses->helper_function_count;
return_value =
ebpf_allocate_trampoline_table(program->helper_function_count, &program->trampoline_table);
if (return_value != EBPF_SUCCESS)
goto Exit;
}
}
return_value = ebpf_update_trampoline_table(
program->trampoline_table, program->program_information_provider_dispatch_table);
if (return_value != EBPF_SUCCESS) {
program->program_invalidated = true;
return;
// Update trampoline table with new helper function addresses.
return_value = ebpf_update_trampoline_table(program->trampoline_table, helper_function_addresses);
if (return_value != EBPF_SUCCESS)
goto Exit;
}
}
program->program_information_provider_dispatch_table = provider_dispatch_table;
program->program_information_binding_context = provider_binding_context;
program->program_information_data = provider_data;
Exit:
program->program_invalidated = (program->program_information_data == NULL);
}
/**
@ -152,6 +162,8 @@ ebpf_program_load_providers(ebpf_program_t* program)
{
ebpf_result_t return_value;
void* provider_binding_context;
ebpf_program_data_t* global_helper_program_data = NULL;
program->program_invalidated = false;
return_value = ebpf_extension_load(
@ -168,6 +180,17 @@ ebpf_program_load_providers(ebpf_program_t* program)
if (return_value != EBPF_SUCCESS)
goto Done;
if (program->global_helper_provider_data == NULL) {
return_value = EBPF_INVALID_ARGUMENT;
goto Done;
}
global_helper_program_data = (ebpf_program_data_t*)program->global_helper_provider_data;
if (global_helper_program_data->helper_function_addresses == NULL) {
return_value = EBPF_INVALID_ARGUMENT;
goto Done;
}
return_value = ebpf_extension_load(
&program->program_information_client,
&program->parameters.program_type,
@ -176,7 +199,7 @@ ebpf_program_load_providers(ebpf_program_t* program)
NULL,
(void**)&program->program_information_binding_context,
&program->program_information_data,
&program->program_information_provider_dispatch_table,
NULL,
_ebpf_program_program_information_provider_changed);
if (return_value != EBPF_SUCCESS)
@ -326,12 +349,13 @@ static ebpf_result_t
_ebpf_program_register_helpers(ebpf_program_t* program)
{
size_t index = 0;
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);
ebpf_program_data_t* global_helper_program_data = (ebpf_program_data_t*)program->global_helper_provider_data->data;
ebpf_helper_function_addresses_t* global_helper_function_addresses =
global_helper_program_data->helper_function_addresses;
size_t count = global_helper_function_addresses->helper_function_count;
for (index = 0; index < count; index++) {
const void* helper = (void*)program->global_helper_provider_dispatch_table->function[index];
const void* helper = (void*)global_helper_function_addresses->helper_function_address[index];
if (helper == NULL)
continue;
@ -390,6 +414,7 @@ Done:
void
ebpf_program_invoke(_In_ const ebpf_program_t* program, _In_ void* context, _Out_ uint32_t* result)
{
*result = 0;
if (!program || program->program_invalidated)
return;
@ -405,9 +430,6 @@ ebpf_program_invoke(_In_ const ebpf_program_t* program, _In_ void* context, _Out
ebpf_result_t
ebpf_program_get_helper_function_address(const ebpf_program_t* program, uint32_t helper_function_id, uint64_t* address)
{
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);
if (helper_function_id > EBPF_MAX_GLOBAL_HELPER_FUNCTION) {
void* function_address;
ebpf_result_t return_value;
@ -418,10 +440,18 @@ ebpf_program_get_helper_function_address(const ebpf_program_t* program, uint32_t
*address = (uint64_t)function_address;
} else {
if (helper_function_id > count) {
ebpf_assert(program->global_helper_provider_data != NULL);
ebpf_program_data_t* global_helper_program_data =
(ebpf_program_data_t*)program->global_helper_provider_data->data;
ebpf_helper_function_addresses_t* global_helper_function_addresses =
global_helper_program_data->helper_function_addresses;
ebpf_assert(global_helper_function_addresses != NULL);
if (helper_function_id > global_helper_function_addresses->helper_function_count) {
return EBPF_INVALID_ARGUMENT;
}
*address = (uint64_t)program->global_helper_provider_dispatch_table->function[helper_function_id];
*address = global_helper_function_addresses->helper_function_address[helper_function_id];
}
return EBPF_SUCCESS;

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

@ -261,7 +261,7 @@ typedef struct _ebpf_operation_get_program_information_reply
{
struct _ebpf_operation_header header;
uint16_t version;
uint16_t size;
size_t size;
uint8_t data[1];
} ebpf_operation_get_program_information_reply_t;
@ -275,6 +275,6 @@ typedef struct _ebpf_operation_get_map_information_reply
{
struct _ebpf_operation_header header;
uint16_t map_count;
uint16_t size;
size_t size;
uint8_t data[1];
} ebpf_operation_get_map_information_reply_t;

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

@ -156,12 +156,13 @@ TEST_CASE("program", "[execution_context]")
ebpf_trampoline_table_t* table = NULL;
ebpf_result_t (*test_function)();
auto provider_function1 = []() { return (ebpf_result_t)TEST_FUNCTION_RETURN; };
ebpf_extension_dispatch_table_t provider_dispatch_table1 = {
0, sizeof(ebpf_extension_dispatch_table_t), provider_function1};
ebpf_result_t (*function_pointer1)() = provider_function1;
const void* helper_functions[] = {(void*)function_pointer1};
ebpf_helper_function_addresses_t helper_function_addresses = {EBPF_COUNT_OF(helper_functions),
(uint64_t*)helper_functions};
REQUIRE(ebpf_allocate_trampoline_table(1, &table) == EBPF_SUCCESS);
REQUIRE(ebpf_update_trampoline_table(table, &provider_dispatch_table1) == EBPF_SUCCESS);
REQUIRE(ebpf_update_trampoline_table(table, &helper_function_addresses) == EBPF_SUCCESS);
REQUIRE(ebpf_get_trampoline_function(table, 0, reinterpret_cast<void**>(&test_function)) == EBPF_SUCCESS);
// Size of the actual function is unknown, but we know the allocation is on page granularity.

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

@ -62,7 +62,7 @@ extern "C"
{
uint16_t version;
uint16_t size;
uint8_t data[1];
void* data;
} ebpf_extension_data_t;
typedef struct _ebpf_trampoline_table ebpf_trampoline_table_t;
@ -75,8 +75,10 @@ extern "C"
typedef struct _GENERIC_MAPPING ebpf_security_generic_mapping_t;
typedef uint32_t ebpf_security_access_mask_t;
typedef struct _ebpf_helper_function_addresses ebpf_helper_function_addresses_t;
/**
* @brief Initialize the eBPF platform abstraction layer.
* @brief Initialize the eBPF platform abstraction layer.
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
* operation.
@ -85,7 +87,7 @@ extern "C"
ebpf_platform_initiate();
/**
* @brief Terminate the eBPF platform abstraction layer.
* @brief Terminate the eBPF platform abstraction layer.
*/
void
ebpf_platform_terminate();
@ -538,10 +540,9 @@ extern "C"
ebpf_interlocked_compare_exchange_int32(_Inout_ volatile int32_t* destination, int32_t exchange, int32_t comperand);
typedef void (*ebpf_extension_change_callback_t)(
void* client_binding_context,
const void* provider_binding_context,
const ebpf_extension_data_t* provider_data,
const ebpf_extension_dispatch_table_t* provider_dispatch_table);
_In_ void* client_binding_context,
_In_ const void* provider_binding_context,
_In_opt_ const ebpf_extension_data_t* provider_data);
/**
* @brief Load an extension and get its dispatch table.
@ -574,7 +575,7 @@ extern "C"
_In_opt_ const ebpf_extension_dispatch_table_t* client_dispatch_table,
_Outptr_opt_ void** provider_binding_context,
_Outptr_ const ebpf_extension_data_t** provider_data,
_Outptr_ const ebpf_extension_dispatch_table_t** provider_dispatch_table,
_Outptr_opt_ const ebpf_extension_dispatch_table_t** provider_dispatch_table,
_In_opt_ ebpf_extension_change_callback_t extension_changed);
/**
@ -667,7 +668,8 @@ extern "C"
*/
ebpf_result_t
ebpf_update_trampoline_table(
_Inout_ ebpf_trampoline_table_t* trampoline_table, _In_ const ebpf_extension_dispatch_table_t* dispatch_table);
_Inout_ ebpf_trampoline_table_t* trampoline_table,
_In_ const ebpf_helper_function_addresses_t* helper_function_addresses);
/**
* @brief Get the address of a trampoline function.

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

@ -3,26 +3,62 @@
// This file contains function implementations for serializing and de-serializing
// various eBPF structures to/from ebpf_operation*_request/response structures.
#include "ebpf_program_types.h"
#include "ebpf_serialize.h"
/**
* @brief Serialized program type descriptor.
*/
typedef struct _ebpf_serialized_program_type_descriptor
{
size_t size;
ebpf_context_descriptor_t context_descriptor;
GUID program_type;
unsigned char is_privileged;
size_t name_length;
uint8_t name[1];
} ebpf_serialized_program_type_descriptor_t;
/**
* @brief Serialized helper function prototype.
*/
typedef struct _ebpf_serialized_helper_function_prototype
{
size_t size;
uint32_t helper_id;
ebpf_return_type_t return_type;
ebpf_argument_type_t arguments[5];
size_t name_length;
uint8_t name[1];
} ebpf_serialized_helper_function_prototype_t;
/**
* @brief Serialized helper function prototypes array.
*/
typedef struct _ebpf_serialized_helper_function_prototype_array
{
size_t size;
uint32_t helper_function_count;
uint8_t prototypes[1];
} ebpf_serialized_helper_function_prototype_array_t;
void
ebpf_map_information_array_free(uint16_t map_count, _In_opt_count_(map_count) ebpf_map_information_t* map_info)
ebpf_map_information_array_free(
uint16_t map_count, _In_opt_count_(map_count) _Post_invalid_ ebpf_map_information_t* map_info)
{
uint16_t map_index;
if (!map_info)
return;
for (map_index = 0; map_index < map_count; map_index++) {
ebpf_free(map_info[map_index].pin_path);
map_info[map_index].pin_path = NULL;
if (map_info != NULL) {
for (map_index = 0; map_index < map_count; map_index++) {
ebpf_free(map_info[map_index].pin_path);
map_info[map_index].pin_path = NULL;
}
ebpf_free(map_info);
}
ebpf_free((void*)map_info);
}
ebpf_result_t
ebpf_serialize_core_map_information_array(
ebpf_serialize_internal_map_information_array(
uint16_t map_count,
_In_count_(map_count) const ebpf_map_information_internal_t* map_info,
_Out_writes_bytes_to_(output_buffer_length, *serialized_data_length) uint8_t* output_buffer,
@ -104,6 +140,9 @@ ebpf_deserialize_map_information_array(
uint8_t* current;
size_t buffer_left;
if (map_count == 0)
goto Exit;
// Allocate the output maps.
result = ebpf_safe_size_t_multiply(sizeof(ebpf_map_information_t), (size_t)map_count, &out_map_size);
if (result != EBPF_SUCCESS)
@ -152,8 +191,6 @@ ebpf_deserialize_map_information_array(
if (source->pin_path_length > 0) {
// Allocate the buffer to hold the pin path in destination map information structure.
destination_pin_path_length = ((size_t)source->pin_path_length) + 1;
if (result != EBPF_SUCCESS)
goto Exit;
destination->pin_path = ebpf_allocate(destination_pin_path_length);
if (destination->pin_path == NULL) {
result = EBPF_NO_MEMORY;
@ -177,8 +214,386 @@ ebpf_deserialize_map_information_array(
out_map_info = NULL;
Exit:
if (out_map_info != NULL)
ebpf_map_information_array_free(map_count, out_map_info);
ebpf_map_information_array_free(map_count, out_map_info);
return result;
}
void
ebpf_program_information_free(_In_opt_ _Post_invalid_ ebpf_program_information_t* program_info)
{
if (program_info != NULL) {
ebpf_free(program_info->program_type_descriptor.context_descriptor);
ebpf_free((void*)program_info->program_type_descriptor.name);
for (uint32_t i = 0; i < program_info->count_of_helpers; i++) {
ebpf_helper_function_prototype_t* helper_prototype = &program_info->helper_prototype[i];
ebpf_free((void*)helper_prototype->name);
}
ebpf_free(program_info->helper_prototype);
ebpf_free(program_info);
}
}
ebpf_result_t
ebpf_serialize_program_information(
_In_ const ebpf_program_information_t* program_info,
_Out_writes_bytes_to_(output_buffer_length, *serialized_data_length) uint8_t* output_buffer,
size_t output_buffer_length,
_Out_ size_t* serialized_data_length,
_Out_ size_t* required_length)
{
ebpf_result_t result = EBPF_SUCCESS;
uint8_t* current = NULL;
const ebpf_program_type_descriptor_t* program_type_descriptor;
ebpf_helper_function_prototype_t* helper_prototype_array;
uint32_t helper_prototype_index;
size_t serialized_program_type_descriptor_length;
size_t program_type_descriptor_name_length;
size_t serialized_helper_prototype_array_length;
ebpf_serialized_program_type_descriptor_t* serialized_program_type_descriptor;
*serialized_data_length = 0;
// Peform sanity check on input program information.
program_type_descriptor = &program_info->program_type_descriptor;
if (program_type_descriptor->name == NULL) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
helper_prototype_array = program_info->helper_prototype;
if (helper_prototype_array != NULL) {
if (program_info->count_of_helpers == 0) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
for (helper_prototype_index = 0; helper_prototype_index < program_info->count_of_helpers;
helper_prototype_index++) {
if (helper_prototype_array[helper_prototype_index].name == NULL) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
}
}
// Compute required length for serialized program information object.
*required_length = 0;
// Compute length for serialized program type descriptor.
serialized_program_type_descriptor_length = 0;
result = ebpf_safe_size_t_add(
serialized_program_type_descriptor_length,
EBPF_OFFSET_OF(ebpf_serialized_program_type_descriptor_t, name),
&serialized_program_type_descriptor_length);
if (result != EBPF_SUCCESS)
goto Exit;
program_type_descriptor_name_length =
strnlen_s(program_type_descriptor->name, EBPF_MAX_PROGRAM_DESCRIPTOR_NAME_LENGTH);
result = ebpf_safe_size_t_add(
serialized_program_type_descriptor_length,
program_type_descriptor_name_length,
&serialized_program_type_descriptor_length);
if (result != EBPF_SUCCESS)
goto Exit;
// Increment required_length by length of serialized program type descriptor.
result = ebpf_safe_size_t_add(*required_length, serialized_program_type_descriptor_length, required_length);
if (result != EBPF_SUCCESS)
goto Exit;
// Compute required length for serialized helper function prototypes array.
serialized_helper_prototype_array_length = 0;
if (helper_prototype_array != NULL) {
result = ebpf_safe_size_t_add(
serialized_helper_prototype_array_length,
EBPF_OFFSET_OF(ebpf_serialized_helper_function_prototype_array_t, prototypes),
&serialized_helper_prototype_array_length);
if (result != EBPF_SUCCESS)
goto Exit;
for (helper_prototype_index = 0; helper_prototype_index < program_info->count_of_helpers;
helper_prototype_index++) {
ebpf_helper_function_prototype_t* helper_prototype = &helper_prototype_array[helper_prototype_index];
result = ebpf_safe_size_t_add(
serialized_helper_prototype_array_length,
EBPF_OFFSET_OF(ebpf_serialized_helper_function_prototype_t, name),
&serialized_helper_prototype_array_length);
if (result != EBPF_SUCCESS)
goto Exit;
result = ebpf_safe_size_t_add(
serialized_helper_prototype_array_length,
strnlen_s(helper_prototype->name, EBPF_MAX_HELPER_FUNCTION_NAME_LENGTH),
&serialized_helper_prototype_array_length);
if (result != EBPF_SUCCESS)
goto Exit;
}
// Increment required length by the length of serialized helper function prototype array.
result = ebpf_safe_size_t_add(*required_length, serialized_helper_prototype_array_length, required_length);
if (result != EBPF_SUCCESS)
goto Exit;
}
if (output_buffer_length < *required_length) {
// Output buffer too small.
result = EBPF_INSUFFICIENT_BUFFER;
goto Exit;
}
*serialized_data_length = *required_length;
current = output_buffer;
memset(output_buffer, 0, output_buffer_length);
// Serialize the program type descriptor.
serialized_program_type_descriptor = (ebpf_serialized_program_type_descriptor_t*)current;
serialized_program_type_descriptor->size = serialized_program_type_descriptor_length;
if (program_type_descriptor->context_descriptor != NULL) {
serialized_program_type_descriptor->context_descriptor = *program_type_descriptor->context_descriptor;
}
serialized_program_type_descriptor->program_type = program_type_descriptor->program_type;
serialized_program_type_descriptor->is_privileged = program_type_descriptor->is_privileged;
serialized_program_type_descriptor->name_length = program_type_descriptor_name_length;
// Copy the program type descriptor name buffer.
memcpy(
serialized_program_type_descriptor->name, program_type_descriptor->name, program_type_descriptor_name_length);
// Move the output buffer current pointer.
current += serialized_program_type_descriptor_length;
if (helper_prototype_array != NULL) {
// Serialize the helper function prototypes array.
ebpf_serialized_helper_function_prototype_array_t* serialized_helper_prototype_array =
(ebpf_serialized_helper_function_prototype_array_t*)current;
serialized_helper_prototype_array->size = serialized_helper_prototype_array_length;
serialized_helper_prototype_array->helper_function_count = program_info->count_of_helpers;
// Move the output buffer current pointer to the beginning of serialized helper function prototypes.
current += EBPF_OFFSET_OF(ebpf_serialized_helper_function_prototype_array_t, prototypes);
for (helper_prototype_index = 0; helper_prototype_index < program_info->count_of_helpers;
helper_prototype_index++) {
ebpf_helper_function_prototype_t* helper_prototype = &helper_prototype_array[helper_prototype_index];
size_t helper_function_name_length =
strnlen_s(helper_prototype->name, EBPF_MAX_HELPER_FUNCTION_NAME_LENGTH);
ebpf_serialized_helper_function_prototype_t* serialized_helper_prototype =
(ebpf_serialized_helper_function_prototype_t*)current;
// Serialize individual helper function prototypes.
serialized_helper_prototype->size =
EBPF_OFFSET_OF(ebpf_serialized_helper_function_prototype_t, name) + helper_function_name_length;
serialized_helper_prototype->helper_id = helper_prototype->helper_id;
serialized_helper_prototype->return_type = helper_prototype->return_type;
for (uint16_t index = 0; index < EBPF_COUNT_OF(helper_prototype->arguments); index++) {
serialized_helper_prototype->arguments[index] = helper_prototype->arguments[index];
}
serialized_helper_prototype->name_length = helper_function_name_length;
// Copy the program type descriptor name buffer.
memcpy(serialized_helper_prototype->name, helper_prototype->name, helper_function_name_length);
// Move the output buffer current pointer.
current += serialized_helper_prototype->size;
}
}
Exit:
return result;
}
ebpf_result_t
ebpf_deserialize_program_information(
size_t input_buffer_length,
_In_reads_bytes_(input_buffer_length) const uint8_t* input_buffer,
_Outptr_ ebpf_program_information_t** program_info)
{
ebpf_result_t result = EBPF_SUCCESS;
ebpf_program_information_t* local_program_info;
const uint8_t* current;
size_t buffer_left;
ebpf_context_descriptor_t* local_context_descriptor;
ebpf_program_type_descriptor_t* local_program_type_descriptor;
const ebpf_serialized_program_type_descriptor_t* serialized_program_type_descriptor;
char* local_program_type_descriptor_name;
ebpf_serialized_helper_function_prototype_array_t* serialized_helper_prototype_array;
uint32_t helper_function_count;
size_t helper_prototype_array_size;
ebpf_helper_function_prototype_t* local_helper_prototype_array;
// Allocate output program information.
local_program_info = (ebpf_program_information_t*)ebpf_allocate(sizeof(ebpf_program_information_t));
if (local_program_info == NULL) {
result = EBPF_NO_MEMORY;
goto Exit;
}
local_program_type_descriptor = &local_program_info->program_type_descriptor;
current = input_buffer;
buffer_left = input_buffer_length;
// Deserialize program type descriptor.
// Check if sufficient input buffer remaining.
if (buffer_left < sizeof(ebpf_serialized_program_type_descriptor_t)) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
serialized_program_type_descriptor = (const ebpf_serialized_program_type_descriptor_t*)current;
local_program_type_descriptor->program_type = serialized_program_type_descriptor->program_type;
local_program_type_descriptor->is_privileged = serialized_program_type_descriptor->is_privileged;
// Allocate and deserialize context_descriptor, if present.
if (serialized_program_type_descriptor->context_descriptor.size != 0) {
local_context_descriptor = (ebpf_context_descriptor_t*)ebpf_allocate(sizeof(ebpf_context_descriptor_t));
if (local_context_descriptor == NULL) {
result = EBPF_NO_MEMORY;
goto Exit;
}
*local_context_descriptor = serialized_program_type_descriptor->context_descriptor;
local_program_type_descriptor->context_descriptor = local_context_descriptor;
}
// Allocate and deserialize program type descriptor name.
if (serialized_program_type_descriptor->name_length == 0) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
// Adjust remaining buffer length.
result = ebpf_safe_size_t_subtract(
buffer_left, EBPF_OFFSET_OF(ebpf_serialized_program_type_descriptor_t, name), &buffer_left);
if (result != EBPF_SUCCESS)
goto Exit;
// Check if sufficient buffer is remaining for program type descriptor name.
if (buffer_left < sizeof(serialized_program_type_descriptor->name_length)) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
// Allocate and deserialize program type descriptor name.
local_program_type_descriptor_name = (char*)ebpf_allocate(serialized_program_type_descriptor->name_length + 1);
if (local_program_type_descriptor_name == NULL) {
result = EBPF_NO_MEMORY;
goto Exit;
}
memcpy(
local_program_type_descriptor_name,
serialized_program_type_descriptor->name,
serialized_program_type_descriptor->name_length);
local_program_type_descriptor->name = local_program_type_descriptor_name;
// Adjust remaining buffer length.
result = ebpf_safe_size_t_subtract(buffer_left, serialized_program_type_descriptor->name_length, &buffer_left);
if (result != EBPF_SUCCESS)
goto Exit;
// Advance the input buffer current pointer to the end of program type descriptor section.
current += serialized_program_type_descriptor->size;
if (buffer_left == 0) {
// No buffer left. This means there are no helper function prototypes in the input buffer.
goto Exit;
}
// Check if sufficient buffer left for ebpf_serialized_helper_function_prototype_array_t.
if (buffer_left < sizeof(ebpf_serialized_helper_function_prototype_array_t)) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
// Deserialize ebpf_serialized_helper_function_prototype_array_t.
serialized_helper_prototype_array = (ebpf_serialized_helper_function_prototype_array_t*)current;
helper_function_count = serialized_helper_prototype_array->helper_function_count;
if (helper_function_count == 0) {
// Serialized buffer present for helper prototypes, but count is zero.
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
local_program_info->count_of_helpers = helper_function_count;
// Advance the input buffer current pointer to the beginning of array of helper function prototypes.
current += EBPF_OFFSET_OF(ebpf_serialized_helper_function_prototype_array_t, prototypes);
// Adjust remaining buffer length.
result = ebpf_safe_size_t_subtract(
buffer_left, EBPF_OFFSET_OF(ebpf_serialized_helper_function_prototype_array_t, prototypes), &buffer_left);
if (result != EBPF_SUCCESS)
goto Exit;
// Allocate array of helper function prototypes.
result = ebpf_safe_size_t_multiply(
helper_function_count, sizeof(ebpf_helper_function_prototype_t), &helper_prototype_array_size);
if (result != EBPF_SUCCESS)
goto Exit;
local_helper_prototype_array = (ebpf_helper_function_prototype_t*)ebpf_allocate(helper_prototype_array_size);
if (local_helper_prototype_array == NULL) {
result = EBPF_NO_MEMORY;
goto Exit;
}
local_program_info->helper_prototype = local_helper_prototype_array;
for (uint16_t helper_function_index = 0; helper_function_index < helper_function_count; helper_function_index++) {
ebpf_serialized_helper_function_prototype_t* serialized_helper_prototype =
(ebpf_serialized_helper_function_prototype_t*)current;
ebpf_helper_function_prototype_t* helper_prototype = &local_helper_prototype_array[helper_function_index];
char* local_helper_function_name;
// Check if sufficient input buffer left for ebpf_serialized_helper_function_prototype_t.
if (buffer_left < sizeof(ebpf_serialized_helper_function_prototype_t)) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
// Serialize helper prototype.
helper_prototype->helper_id = serialized_helper_prototype->helper_id;
helper_prototype->return_type = serialized_helper_prototype->return_type;
for (int i = 0; i < EBPF_COUNT_OF(helper_prototype->arguments); i++)
helper_prototype->arguments[i] = serialized_helper_prototype->arguments[i];
// Adjust remaining buffer length.
result = ebpf_safe_size_t_subtract(
buffer_left, EBPF_OFFSET_OF(ebpf_serialized_helper_function_prototype_t, name), &buffer_left);
if (result != EBPF_SUCCESS)
goto Exit;
// Check if enough buffer left for helper function name.
if (buffer_left < serialized_helper_prototype->name_length) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
// Allocate buffer and serialize helper function name.
local_helper_function_name = (char*)ebpf_allocate(serialized_helper_prototype->name_length + 1);
if (local_helper_function_name == NULL) {
result = EBPF_NO_MEMORY;
goto Exit;
}
memcpy(local_helper_function_name, serialized_helper_prototype->name, serialized_helper_prototype->name_length);
helper_prototype->name = local_helper_function_name;
// Adjust remaining buffer length.
result = ebpf_safe_size_t_subtract(buffer_left, serialized_helper_prototype->name_length, &buffer_left);
if (result != EBPF_SUCCESS)
goto Exit;
// Advance the current pointer to the end of the helper function prototype.
current += serialized_helper_prototype->size;
}
Exit:
if (result == EBPF_SUCCESS) {
*program_info = local_program_info;
local_program_info = NULL;
}
ebpf_program_information_free(local_program_info);
return result;
}

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

@ -15,7 +15,7 @@ extern "C"
#endif
/**
* @brief eBPF Core Map Information
* @brief eBPF Internal Map Information
*/
typedef struct _ebpf_map_information_internal
{
@ -47,7 +47,7 @@ extern "C"
* @retval EBPF_ERROR_INSUFFICIENT_BUFFER The output buffer is insufficient to store serialized data.
*/
ebpf_result_t
ebpf_serialize_core_map_information_array(
ebpf_serialize_internal_map_information_array(
uint16_t map_count,
_In_count_(map_count) const ebpf_map_information_internal_t* map_info,
_Out_writes_bytes_to_(output_buffer_length, *serialized_data_length) uint8_t* output_buffer,
@ -82,7 +82,55 @@ extern "C"
* @param[in] map_info Map to be freed.
*/
void
ebpf_map_information_array_free(uint16_t map_count, _In_opt_count_(map_count) ebpf_map_information_t* map_info);
ebpf_map_information_array_free(
uint16_t map_count, _In_opt_count_(map_count) _Post_invalid_ ebpf_map_information_t* map_info);
/**
* @brief Serialize ebpf_program_information_t onto output buffer.
*
* @param[in] program_info Pointer to program_map_information_t to serialize.
* @param[out] output_buffer Caller specified output buffer to write serialized data into.
* @param[in] output_buffer_length Output buffer length.
* @param[out] serialized_data_length Length of successfully serialized data.
* @param[out] required_length Length of buffer required to serialize input array.
*
* @retval EBPF_SUCCESS The serialization was successful.
* @retval EBPF_INVALID_ARGUMENT One or more input parameters are incorrect.
* @retval EBPF_ERROR_INSUFFICIENT_BUFFER The output buffer is insufficient to store serialized data.
*/
ebpf_result_t
ebpf_serialize_program_information(
_In_ const ebpf_program_information_t* program_info,
_Out_writes_bytes_to_(output_buffer_length, *serialized_data_length) uint8_t* output_buffer,
size_t output_buffer_length,
_Out_ size_t* serialized_data_length,
_Out_ size_t* required_length);
/**
* @brief Deserialize input buffer to an array of ebpf_map_information_t.
*
* @param[in] input_buffer_length Input buffer length.
* @param[in] input_buffer Input buffer that will be de-serialized.
* @param[out] program_info Pointer to ebpf_program_information_t deserialized from input buffer.
*
* @retval EBPF_SUCCESS The de-serialization was successful.
* @retval EBPF_INVALID_ARGUMENT One or more input parameters are incorrect.
* @retval EBPF_NO_MEMORY Output array could not be allocated.
*/
ebpf_result_t
ebpf_deserialize_program_information(
size_t input_buffer_length,
_In_reads_bytes_(input_buffer_length) const uint8_t* input_buffer,
_Outptr_ ebpf_program_information_t** program_info);
/**
* @brief Helper Function to free ebpf_program_information_t allocated by
* ebpf_deserialize_program_information().
*
* @param[in] program_info Program information to be freed.
*/
void
ebpf_program_information_free(_In_opt_ _Post_invalid_ ebpf_program_information_t* program_info);
#ifdef __cplusplus
}

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

@ -2,6 +2,7 @@
// SPDX-License-Identifier: MIT
#include "ebpf_platform.h"
#include "ebpf_program_types.h"
#include "ebpf_epoch.h"
#pragma pack(push)
@ -61,12 +62,12 @@ ebpf_free_trampoline_table(_In_opt_ _Post_invalid_ ebpf_trampoline_table_t* tram
ebpf_result_t
ebpf_update_trampoline_table(
_Inout_ ebpf_trampoline_table_t* trampoline_table, _In_ const ebpf_extension_dispatch_table_t* dispatch_table)
_Inout_ ebpf_trampoline_table_t* trampoline_table,
_In_ const ebpf_helper_function_addresses_t* helper_function_addresses)
{
#if defined(_AMD64_)
size_t function_count = (dispatch_table->size - EBPF_OFFSET_OF(ebpf_extension_dispatch_table_t, function)) /
sizeof(dispatch_table->function[0]);
size_t function_count = helper_function_addresses->helper_function_count;
ebpf_trampoline_entry_t* local_entries;
ebpf_result_t return_value;
@ -92,7 +93,7 @@ ebpf_update_trampoline_table(
local_entries[index].load_rax = 0xa148;
local_entries[index].indirect_address = &local_entries[index].address;
local_entries[index].jmp_rax = 0xe0ff;
local_entries[index].address = (void*)dispatch_table->function[index];
local_entries[index].address = (void*)helper_function_addresses->helper_function_address[index];
}
Exit:

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

@ -48,8 +48,7 @@ _ebpf_extension_client_notify_change(ebpf_extension_client_t* client_context)
client_context->extension_change_callback(
client_context->client_binding_context,
client_context->provider_binding_context,
client_context->provider_data,
client_context->provider_dispatch_table);
client_context->provider_data);
}
NTSTATUS
@ -119,15 +118,20 @@ ebpf_extension_load(
_In_opt_ const ebpf_extension_dispatch_table_t* client_dispatch_table,
_Outptr_opt_ void** provider_binding_context,
_Outptr_ const ebpf_extension_data_t** provider_data,
_Outptr_ const ebpf_extension_dispatch_table_t** provider_dispatch_table,
_Outptr_opt_ const ebpf_extension_dispatch_table_t** provider_dispatch_table,
_In_opt_ ebpf_extension_change_callback_t extension_changed)
{
ebpf_result_t return_value;
ebpf_extension_client_t* local_client_context;
ebpf_extension_client_t* local_client_context = NULL;
NPI_CLIENT_CHARACTERISTICS* client_characteristics;
NPI_REGISTRATION_INSTANCE* client_registration_instance;
NTSTATUS status;
if (provider_binding_context == NULL) {
return_value = EBPF_INVALID_ARGUMENT;
goto Done;
}
local_client_context = ebpf_allocate(sizeof(ebpf_extension_client_t));
if (!local_client_context) {
@ -184,7 +188,8 @@ ebpf_extension_load(
*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;
if (provider_dispatch_table != NULL)
*provider_dispatch_table = local_client_context->provider_dispatch_table;
*client_context = local_client_context;
local_client_context = NULL;
return_value = EBPF_SUCCESS;

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

@ -195,21 +195,25 @@ TEST_CASE("trampoline_test", "[platform]")
ebpf_trampoline_table_t* table = NULL;
ebpf_result_t (*test_function)();
auto provider_function1 = []() { return EBPF_SUCCESS; };
auto provider_function2 = []() { return EBPF_OBJECT_ALREADY_EXISTS; };
ebpf_result_t (*function_pointer1)() = provider_function1;
const void* helper_functions1[] = {(void*)function_pointer1};
ebpf_helper_function_addresses_t helper_function_addresses1 = {EBPF_COUNT_OF(helper_functions1),
(uint64_t*)helper_functions1};
ebpf_extension_dispatch_table_t provider_dispatch_table1 = {
0, sizeof(ebpf_extension_dispatch_table_t), provider_function1};
ebpf_extension_dispatch_table_t provider_dispatch_table2 = {
0, sizeof(ebpf_extension_dispatch_table_t), provider_function2};
auto provider_function2 = []() { return EBPF_OBJECT_ALREADY_EXISTS; };
ebpf_result_t (*function_pointer2)() = provider_function2;
const void* helper_functions2[] = {(void*)function_pointer2};
ebpf_helper_function_addresses_t helper_function_addresses2 = {EBPF_COUNT_OF(helper_functions1),
(uint64_t*)helper_functions2};
REQUIRE(ebpf_allocate_trampoline_table(1, &table) == EBPF_SUCCESS);
REQUIRE(ebpf_update_trampoline_table(table, &provider_dispatch_table1) == EBPF_SUCCESS);
REQUIRE(ebpf_update_trampoline_table(table, &helper_function_addresses1) == EBPF_SUCCESS);
REQUIRE(ebpf_get_trampoline_function(table, 0, reinterpret_cast<void**>(&test_function)) == EBPF_SUCCESS);
// Verify that the trampoline function invokes the provider function
REQUIRE(test_function() == EBPF_SUCCESS);
REQUIRE(ebpf_update_trampoline_table(table, &provider_dispatch_table2) == EBPF_SUCCESS);
REQUIRE(ebpf_update_trampoline_table(table, &helper_function_addresses2) == EBPF_SUCCESS);
// Verify that the trampoline function now invokes the new provider function
REQUIRE(test_function() == EBPF_OBJECT_ALREADY_EXISTS);
@ -234,11 +238,10 @@ TEST_CASE("program_type_info", "[platform]")
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
};
ebpf_context_descriptor_t context_descriptor{
sizeof(xdp_md_t),
EBPF_OFFSET_OF(xdp_md_t, data),
EBPF_OFFSET_OF(xdp_md_t, data_end),
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
ebpf_context_descriptor_t context_descriptor{sizeof(xdp_md_t),
EBPF_OFFSET_OF(xdp_md_t, data),
EBPF_OFFSET_OF(xdp_md_t, data_end),
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
ebpf_program_type_descriptor_t program_type{"xdp", &context_descriptor};
ebpf_program_information_t program_information{program_type, _countof(helper_functions), helper_functions};
ebpf_program_information_t* new_program_information = nullptr;
@ -316,7 +319,7 @@ TEST_CASE("serialize_map_test", "[platform]")
_test_helper test_helper;
const int map_count = 10;
ebpf_map_information_internal_t core_map_info_array[map_count] = {};
ebpf_map_information_internal_t internal_map_info_array[map_count] = {};
std::string pin_path_prefix = "\\ebpf\\map\\";
std::vector<std::string> pin_paths;
size_t buffer_length = 0;
@ -331,7 +334,7 @@ TEST_CASE("serialize_map_test", "[platform]")
}
for (int i = 0; i < map_count; i++) {
ebpf_map_information_internal_t* map_info = &core_map_info_array[i];
ebpf_map_information_internal_t* map_info = &internal_map_info_array[i];
map_info->definition.size = (i + 1) * 32;
map_info->definition.type = static_cast<ebpf_map_type_t>(i % (EBPF_MAP_TYPE_ARRAY + 1));
map_info->definition.key_size = i + 1;
@ -343,8 +346,8 @@ TEST_CASE("serialize_map_test", "[platform]")
}
// Serialize.
ebpf_result_t result = ebpf_serialize_core_map_information_array(
map_count, core_map_info_array, buffer, buffer_length, &serialized_length, &required_length);
ebpf_result_t result = ebpf_serialize_internal_map_information_array(
map_count, internal_map_info_array, buffer, buffer_length, &serialized_length, &required_length);
REQUIRE(result == EBPF_INSUFFICIENT_BUFFER);
buffer = static_cast<uint8_t*>(calloc(required_length, 1));
@ -354,8 +357,8 @@ TEST_CASE("serialize_map_test", "[platform]")
}
buffer_length = required_length;
result = ebpf_serialize_core_map_information_array(
map_count, core_map_info_array, buffer, buffer_length, &serialized_length, &required_length);
result = ebpf_serialize_internal_map_information_array(
map_count, internal_map_info_array, buffer, buffer_length, &serialized_length, &required_length);
REQUIRE(result == EBPF_SUCCESS);
// Deserialize.
@ -364,7 +367,7 @@ TEST_CASE("serialize_map_test", "[platform]")
// Verify de-serialized map info array matches input.
for (int i = 0; i < map_count; i++) {
ebpf_map_information_internal_t* input_map_info = &core_map_info_array[i];
ebpf_map_information_internal_t* input_map_info = &internal_map_info_array[i];
ebpf_map_information_t* map_info = &map_info_array[i];
REQUIRE(memcmp(&map_info->definition, &input_map_info->definition, sizeof(ebpf_map_definition_t)) == 0);
REQUIRE(strnlen_s(map_info->pin_path, EBPF_MAX_PIN_PATH_LENGTH) == input_map_info->pin_path.length);
@ -374,6 +377,85 @@ TEST_CASE("serialize_map_test", "[platform]")
// Free de-serialized map info array.
ebpf_map_information_array_free(map_count, map_info_array);
if (buffer != nullptr)
free(buffer);
free(buffer);
}
TEST_CASE("serialize_program_information_test", "[platform]")
{
_test_helper test_helper;
ebpf_helper_function_prototype_t helper_prototype[] = {
{1000,
"helper_0",
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
{1001,
"helper_1",
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE}}};
// The values of the fields in the context_descriptor variable are completely arbitrary
// and have no effect on the test.
ebpf_context_descriptor_t context_descriptor = {32, 0, 8, -1};
GUID program_type_test = {0x7ebe418c, 0x76dd, 0x4c2c, {0x99, 0xbc, 0x5c, 0x48, 0xa2, 0x30, 0x4b, 0x90}};
ebpf_program_type_descriptor_t program_type = {"unit_test_program", &context_descriptor, program_type_test};
ebpf_program_information_t in_program_info = {program_type, EBPF_COUNT_OF(helper_prototype), helper_prototype};
size_t buffer_length = 0;
uint8_t* buffer = nullptr;
size_t required_length;
size_t serialized_length;
ebpf_program_information_t* out_program_info;
// Serialize.
ebpf_result_t result = ebpf_serialize_program_information(
&in_program_info, buffer, buffer_length, &serialized_length, &required_length);
REQUIRE(result == EBPF_INSUFFICIENT_BUFFER);
buffer = static_cast<uint8_t*>(calloc(required_length, 1));
_Analysis_assume_(buffer != nullptr);
buffer_length = required_length;
result = ebpf_serialize_program_information(
&in_program_info, buffer, buffer_length, &serialized_length, &required_length);
REQUIRE(result == EBPF_SUCCESS);
// Deserialize.
result = ebpf_deserialize_program_information(serialized_length, buffer, &out_program_info);
REQUIRE(result == EBPF_SUCCESS);
// Verify de-serialized program information matches input.
REQUIRE(
in_program_info.program_type_descriptor.program_type == out_program_info->program_type_descriptor.program_type);
REQUIRE(
in_program_info.program_type_descriptor.is_privileged ==
out_program_info->program_type_descriptor.is_privileged);
REQUIRE(in_program_info.program_type_descriptor.context_descriptor != nullptr);
REQUIRE(
memcmp(
in_program_info.program_type_descriptor.context_descriptor,
out_program_info->program_type_descriptor.context_descriptor,
sizeof(ebpf_context_descriptor_t)) == 0);
REQUIRE(
strncmp(
in_program_info.program_type_descriptor.name,
out_program_info->program_type_descriptor.name,
EBPF_MAX_PROGRAM_DESCRIPTOR_NAME_LENGTH) == 0);
REQUIRE(in_program_info.count_of_helpers == out_program_info->count_of_helpers);
REQUIRE(out_program_info->helper_prototype != nullptr);
for (uint32_t i = 0; i < in_program_info.count_of_helpers; i++) {
ebpf_helper_function_prototype_t* in_prototype = &in_program_info.helper_prototype[i];
ebpf_helper_function_prototype_t* out_prototype = &out_program_info->helper_prototype[i];
REQUIRE(in_prototype->helper_id == out_prototype->helper_id);
REQUIRE(in_prototype->return_type == out_prototype->return_type);
for (int j = 0; j < _countof(in_prototype->arguments); j++)
REQUIRE(in_prototype->arguments[j] == out_prototype->arguments[j]);
REQUIRE(out_prototype->name != nullptr);
REQUIRE(strncmp(in_prototype->name, out_prototype->name, EBPF_MAX_HELPER_FUNCTION_NAME_LENGTH) == 0);
}
// Free de-serialized program information.
ebpf_program_information_free(out_program_info);
free(buffer);
}

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

@ -36,17 +36,22 @@ ebpf_extension_load(
_In_opt_ const ebpf_extension_dispatch_table_t* client_dispatch_table,
_Outptr_opt_ void** provider_binding_context,
_Outptr_ const ebpf_extension_data_t** provider_data,
_Outptr_ const ebpf_extension_dispatch_table_t** provider_dispatch_table,
_Outptr_opt_ const ebpf_extension_dispatch_table_t** provider_dispatch_table,
_In_opt_ ebpf_extension_change_callback_t extension_changed)
{
ebpf_result_t return_value;
ebpf_lock_state_t state;
ebpf_lock_state_t state = 0;
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;
UNREFERENCED_PARAMETER(extension_changed);
if (provider_binding_context == NULL) {
return_value = EBPF_INVALID_ARGUMENT;
goto Done;
}
state = ebpf_lock_lock(&_ebpf_provider_table_lock);
if (!_ebpf_provider_table) {
@ -102,7 +107,8 @@ ebpf_extension_load(
*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;
if (provider_dispatch_table != NULL)
*provider_dispatch_table = local_extension_provider->provider_dispatch_table;
Done:
if (local_extension_provider && local_extension_client) {

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

@ -48,11 +48,48 @@ static ebpf_ext_attach_hook_provider_registration_t* _ebpf_xdp_hook_provider_reg
static ebpf_ext_attach_hook_provider_registration_t* _ebpf_bind_hook_provider_registration = NULL;
static ebpf_extension_provider_t* _ebpf_xdp_program_information_provider = NULL;
static ebpf_extension_provider_t* _ebpf_bind_program_information_provider = NULL;
static ebpf_extension_data_t* _ebpf_xdp_program_information_provider_data = NULL;
static ebpf_extension_data_t* _ebpf_bind_program_information_provider_data = NULL;
#define RTL_COUNT_OF(arr) (sizeof(arr) / sizeof(arr[0]))
#define NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION 0
static ebpf_helper_function_prototype_t _ebpf_map_helper_function_prototype[] = {
{1,
"ebpf_map_lookup_element",
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
{2,
"ebpf_map_update_element",
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE}},
{3,
"ebpf_map_delete_element",
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}}};
static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {sizeof(xdp_md_t),
EBPF_OFFSET_OF(xdp_md_t, data),
EBPF_OFFSET_OF(xdp_md_t, data_end),
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
static ebpf_program_information_t _ebpf_xdp_program_information = {{"xdp", &_ebpf_xdp_context_descriptor, {0}},
EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
_ebpf_map_helper_function_prototype};
static ebpf_program_data_t _ebpf_xdp_program_data = {&_ebpf_xdp_program_information, NULL};
static ebpf_extension_data_t _ebpf_xdp_program_information_provider_data = {
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_xdp_program_data), &_ebpf_xdp_program_data};
static ebpf_context_descriptor_t _ebpf_bind_context_descriptor = {
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
static ebpf_program_information_t _ebpf_bind_program_information = {{"bind", &_ebpf_bind_context_descriptor, {0}},
EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
_ebpf_map_helper_function_prototype};
static ebpf_program_data_t _ebpf_bind_program_data = {&_ebpf_bind_program_information, NULL};
static ebpf_extension_data_t _ebpf_bind_program_information_provider_data = {
NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_bind_program_data), &_ebpf_bind_program_data};
// Callout and sublayer GUIDs
// 7c7b3fb9-3331-436a-98e1-b901df457fff
@ -637,85 +674,24 @@ net_ebpf_ext_program_information_provider_unregister()
{
ebpf_provider_unload(_ebpf_xdp_program_information_provider);
ebpf_provider_unload(_ebpf_bind_program_information_provider);
ebpf_free(_ebpf_xdp_program_information_provider_data);
_ebpf_xdp_program_information_provider_data = NULL;
ebpf_free(_ebpf_bind_program_information_provider_data);
_ebpf_bind_program_information_provider_data = NULL;
}
static ebpf_result_t
_net_ebpf_ext_program_information_encode_xdp()
{
ebpf_result_t return_value;
const uint8_t* buffer = _ebpf_encoded_xdp_program_information_data;
unsigned long buffer_size = sizeof(_ebpf_encoded_xdp_program_information_data);
_ebpf_xdp_program_information_provider_data =
(ebpf_extension_data_t*)ebpf_allocate(EBPF_OFFSET_OF(ebpf_extension_data_t, data) + buffer_size);
if (_ebpf_xdp_program_information_provider_data == NULL) {
return_value = EBPF_NO_MEMORY;
goto Done;
}
_ebpf_xdp_program_information_provider_data->size =
(uint16_t)(EBPF_OFFSET_OF(ebpf_extension_data_t, data) + buffer_size);
_ebpf_xdp_program_information_provider_data->version = 0;
memcpy(_ebpf_xdp_program_information_provider_data->data, buffer, buffer_size);
return_value = EBPF_SUCCESS;
Done:
return return_value;
}
static ebpf_result_t
_net_ebpf_ext_program_information_encode_bind()
{
ebpf_result_t return_value;
const uint8_t* buffer = _ebpf_encoded_bind_program_information_data;
unsigned long buffer_size = sizeof(_ebpf_encoded_bind_program_information_data);
_ebpf_bind_program_information_provider_data =
(ebpf_extension_data_t*)ebpf_allocate(EBPF_OFFSET_OF(ebpf_extension_data_t, data) + buffer_size);
if (_ebpf_bind_program_information_provider_data == NULL) {
return_value = EBPF_NO_MEMORY;
goto Done;
}
_ebpf_bind_program_information_provider_data->size =
(uint16_t)(EBPF_OFFSET_OF(ebpf_extension_data_t, data) + buffer_size);
_ebpf_bind_program_information_provider_data->version = 0;
memcpy(_ebpf_bind_program_information_provider_data->data, buffer, buffer_size);
return_value = EBPF_SUCCESS;
Done:
return return_value;
}
NTSTATUS
net_ebpf_ext_program_information_provider_register()
{
ebpf_result_t return_value;
ebpf_extension_data_t* provider_data;
ebpf_program_data_t* program_data;
return_value = _net_ebpf_ext_program_information_encode_xdp();
if (return_value != EBPF_SUCCESS) {
goto Done;
}
return_value = _net_ebpf_ext_program_information_encode_bind();
if (return_value != EBPF_SUCCESS) {
goto Done;
}
provider_data = &_ebpf_xdp_program_information_provider_data;
program_data = (ebpf_program_data_t*)provider_data->data;
program_data->program_information->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_XDP;
return_value = ebpf_provider_load(
&_ebpf_xdp_program_information_provider,
&EBPF_PROGRAM_TYPE_XDP,
NULL,
_ebpf_xdp_program_information_provider_data,
&_ebpf_xdp_program_information_provider_data,
NULL,
NULL,
NULL,
@ -724,11 +700,16 @@ net_ebpf_ext_program_information_provider_register()
if (return_value != EBPF_SUCCESS) {
goto Done;
}
provider_data = &_ebpf_bind_program_information_provider_data;
program_data = (ebpf_program_data_t*)provider_data->data;
program_data->program_information->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_BIND;
return_value = ebpf_provider_load(
&_ebpf_bind_program_information_provider,
&EBPF_PROGRAM_TYPE_BIND,
NULL,
_ebpf_bind_program_information_provider_data,
&_ebpf_bind_program_information_provider_data,
NULL,
NULL,
NULL,
@ -741,8 +722,6 @@ net_ebpf_ext_program_information_provider_register()
Done:
if (return_value != EBPF_SUCCESS) {
net_ebpf_ext_program_information_provider_unregister();
ebpf_free(_ebpf_xdp_program_information_provider_data);
ebpf_free(_ebpf_bind_program_information_provider_data);
return STATUS_UNSUCCESSFUL;
} else
return STATUS_SUCCESS;

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

@ -82,7 +82,7 @@
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -124,6 +124,7 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWarningAsError>true</TreatWarningAsError>

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

@ -99,103 +99,71 @@ typedef class _single_instance_hook
ebpf_handle_t link_handle;
} single_instance_hook_t;
#define TEST_NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION 0
static ebpf_helper_function_prototype_t _ebpf_map_helper_function_prototype[] = {
{1,
"ebpf_map_lookup_element",
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
{2,
"ebpf_map_update_element",
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE}},
{3,
"ebpf_map_delete_element",
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}}};
static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {sizeof(xdp_md_t),
EBPF_OFFSET_OF(xdp_md_t, data),
EBPF_OFFSET_OF(xdp_md_t, data_end),
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
static ebpf_program_information_t _ebpf_xdp_program_information = {{"xdp", &_ebpf_xdp_context_descriptor, {0}},
EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
_ebpf_map_helper_function_prototype};
static ebpf_program_data_t _ebpf_xdp_program_data = {&_ebpf_xdp_program_information, NULL};
static ebpf_extension_data_t _ebpf_xdp_program_information_provider_data = {
TEST_NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_xdp_program_data), &_ebpf_xdp_program_data};
static ebpf_context_descriptor_t _ebpf_bind_context_descriptor = {
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
static ebpf_program_information_t _ebpf_bind_program_information = {{"bind", &_ebpf_bind_context_descriptor, {0}},
EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
_ebpf_map_helper_function_prototype};
static ebpf_program_data_t _ebpf_bind_program_data = {&_ebpf_bind_program_information, NULL};
static ebpf_extension_data_t _ebpf_bind_program_information_provider_data = {
TEST_NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION, sizeof(_ebpf_bind_program_data), &_ebpf_bind_program_data};
typedef class _program_information_provider
{
public:
_program_information_provider(ebpf_program_type_t program_type) : program_type(program_type)
{
if (program_type == EBPF_PROGRAM_TYPE_XDP)
encode_xdp();
else if (program_type == EBPF_PROGRAM_TYPE_BIND)
encode_bind();
ebpf_program_data_t* program_data;
if (program_type == EBPF_PROGRAM_TYPE_XDP) {
provider_data = &_ebpf_xdp_program_information_provider_data;
program_data = (ebpf_program_data_t*)provider_data->data;
program_data->program_information->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_XDP;
} else if (program_type == EBPF_PROGRAM_TYPE_BIND) {
provider_data = &_ebpf_bind_program_information_provider_data;
program_data = (ebpf_program_data_t*)provider_data->data;
program_data->program_information->program_type_descriptor.program_type = EBPF_PROGRAM_TYPE_BIND;
}
REQUIRE(
ebpf_provider_load(
&provider,
&program_type,
nullptr,
reinterpret_cast<ebpf_extension_data_t*>(provider_data.data()),
nullptr,
nullptr,
nullptr,
nullptr) == EBPF_SUCCESS);
ebpf_provider_load(&provider, &program_type, nullptr, provider_data, nullptr, nullptr, nullptr, nullptr) ==
EBPF_SUCCESS);
}
~_program_information_provider() { ebpf_provider_unload(provider); }
private:
void
encode_bind()
{
ebpf_helper_function_prototype_t helper_functions[] = {
{1,
"ebpf_map_lookup_element",
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
{2,
"ebpf_map_update_element",
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE}},
{3,
"ebpf_map_delete_element",
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
};
ebpf_context_descriptor_t context_descriptor{
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
ebpf_program_type_descriptor_t program_type_descriptor{"bind", &context_descriptor, EBPF_PROGRAM_TYPE_BIND};
ebpf_program_information_t program_information{
program_type_descriptor, _countof(helper_functions), helper_functions};
uint8_t* buffer;
unsigned long buffer_size;
REQUIRE(ebpf_program_information_encode(&program_information, &buffer, &buffer_size) == EBPF_SUCCESS);
// Capture the buffer so that it's freed on scope exit.
ebpf_memory_t memory(buffer);
provider_data.resize(EBPF_OFFSET_OF(ebpf_extension_data_t, data) + buffer_size);
ebpf_extension_data_t* extension_data = reinterpret_cast<ebpf_extension_data_t*>(provider_data.data());
extension_data->size = static_cast<uint16_t>(provider_data.size());
extension_data->version = 0;
memcpy(extension_data->data, buffer, buffer_size);
}
void
encode_xdp()
{
ebpf_helper_function_prototype_t helper_functions[] = {
{1,
"ebpf_map_lookup_element",
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
{2,
"ebpf_map_update_element",
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_VALUE}},
{3,
"ebpf_map_delete_element",
EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
};
ebpf_context_descriptor_t context_descriptor{sizeof(xdp_md_t),
EBPF_OFFSET_OF(xdp_md_t, data),
EBPF_OFFSET_OF(xdp_md_t, data_end),
EBPF_OFFSET_OF(xdp_md_t, data_meta)};
ebpf_program_type_descriptor_t program_type_descriptor{"xdp", &context_descriptor, EBPF_PROGRAM_TYPE_XDP};
ebpf_program_information_t program_information{
program_type_descriptor, _countof(helper_functions), helper_functions};
uint8_t* buffer;
unsigned long buffer_size;
REQUIRE(ebpf_program_information_encode(&program_information, &buffer, &buffer_size) == EBPF_SUCCESS);
// Capture the buffer so that it's freed on scope exit.
ebpf_memory_t memory(buffer);
provider_data.resize(EBPF_OFFSET_OF(ebpf_extension_data_t, data) + buffer_size);
ebpf_extension_data_t* extension_data = reinterpret_cast<ebpf_extension_data_t*>(provider_data.data());
extension_data->size = static_cast<uint16_t>(provider_data.size());
extension_data->version = 0;
memcpy(extension_data->data, buffer, buffer_size);
}
ebpf_program_type_t program_type;
std::vector<uint8_t> provider_data;
ebpf_extension_data_t* provider_data;
ebpf_extension_provider_t* provider;
} program_information_provider_t;

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

@ -83,7 +83,7 @@
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
@ -129,6 +129,7 @@
<TreatWarningAsError>true</TreatWarningAsError>
<LanguageStandard>stdcpp17</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

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

@ -48,7 +48,7 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
@ -62,6 +62,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)external\ebpf-verifier\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>