Register program type specific helper functions to uBPF in interpreted mode (#402)

* Register program type specific helper functions to uBPF in interpreted mode.

Co-authored-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Shankar Seal 2021-08-23 12:24:45 -07:00 коммит произвёл GitHub
Родитель b917cc5ba8
Коммит 5519c26f5b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 319 добавлений и 99 удалений

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

@ -52,23 +52,21 @@ static ebpf_helper_function_prototype_t _ebpf_map_helper_function_prototype[] =
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_OF_PROGRAMS, EBPF_ARGUMENT_TYPE_ANYTHING}},
};
static ebpf_program_info_t _ebpf_global_helper_program_info = {
{"global_helper", NULL, {0}},
EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
_ebpf_map_helper_function_prototype};
static ebpf_program_info_t _ebpf_global_helper_program_info = {{"global_helper", NULL, {0}},
EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
_ebpf_map_helper_function_prototype};
static const void* _ebpf_general_helpers[] = {
NULL,
(void*)&_ebpf_core_map_find_element,
(void*)&_ebpf_core_map_update_element,
(void*)&_ebpf_core_map_delete_element,
(void*)&_ebpf_core_tail_call};
static const void* _ebpf_general_helpers[] = {NULL,
(void*)&_ebpf_core_map_find_element,
(void*)&_ebpf_core_map_update_element,
(void*)&_ebpf_core_map_delete_element,
(void*)&_ebpf_core_tail_call};
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_general_helpers), (uint64_t*)_ebpf_general_helpers};
static ebpf_program_data_t _ebpf_global_helper_function_program_data = {
&_ebpf_global_helper_program_info, &_ebpf_global_helper_function_dispatch_table};
static ebpf_program_data_t _ebpf_global_helper_function_program_data = {&_ebpf_global_helper_program_info,
&_ebpf_global_helper_function_dispatch_table};
static ebpf_extension_data_t _ebpf_global_helper_function_extension_data = {
EBPF_CORE_GLOBAL_HELPER_EXTENSION_VERSION,
@ -164,13 +162,7 @@ _ebpf_core_protocol_load_code(_In_ const ebpf_operation_load_code_request_t* req
code = (uint8_t*)request->code;
code_length = request->header.length - EBPF_OFFSET_OF(ebpf_operation_load_code_request_t, code);
if (request->code_type == EBPF_CODE_NATIVE) {
retval = ebpf_program_load_machine_code(program, code, code_length);
} else {
retval =
ebpf_program_load_byte_code(program, (ebpf_instruction_t*)code, code_length / sizeof(ebpf_instruction_t));
}
retval = ebpf_program_load_code(program, request->code_type, code, code_length);
if (retval != EBPF_SUCCESS)
goto Done;
@ -216,12 +208,13 @@ _ebpf_core_protocol_resolve_helper(
if (return_value != EBPF_SUCCESS)
goto Done;
for (helper_index = 0; helper_index < count_of_helpers; helper_index++) {
return_value = ebpf_program_get_helper_function_address(
program, request_helper_ids[helper_index], &reply->address[helper_index]);
if (return_value != EBPF_SUCCESS)
goto Done;
}
return_value = ebpf_program_set_helper_function_ids(program, count_of_helpers, request_helper_ids);
if (return_value != EBPF_SUCCESS)
goto Done;
return_value = ebpf_program_get_helper_function_addresses(program, count_of_helpers, reply->address);
if (return_value != EBPF_SUCCESS)
goto Done;
Done:
if (return_value == EBPF_SUCCESS)
@ -662,9 +655,9 @@ static ebpf_result_t
_ebpf_core_protocol_update_pinning(_In_ const struct _ebpf_operation_update_map_pinning_request* request)
{
ebpf_result_t retval;
const ebpf_utf8_string_t name = {
(uint8_t*)request->name,
request->header.length - EBPF_OFFSET_OF(ebpf_operation_update_pinning_request_t, name)};
const ebpf_utf8_string_t name = {(uint8_t*)request->name,
request->header.length -
EBPF_OFFSET_OF(ebpf_operation_update_pinning_request_t, name)};
ebpf_object_t* object = NULL;
if (name.length == 0) {

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

@ -41,17 +41,25 @@ typedef struct _ebpf_program
ebpf_extension_client_t* program_info_client;
const void* program_info_binding_context;
const ebpf_extension_data_t* program_info_provider_data;
uint32_t helper_function_count;
// Program type specific helper function count.
uint32_t provider_helper_function_count;
bool program_invalidated;
ebpf_trampoline_table_t* trampoline_table;
// Array of helper function ids referred by this program.
size_t helper_function_count;
uint32_t* helper_function_ids;
ebpf_epoch_work_item_t* cleanup_work_item;
ebpf_list_entry_t links;
ebpf_lock_t links_lock;
} ebpf_program_t;
static ebpf_result_t
_ebpf_program_register_helpers(ebpf_program_t* program);
static void
_ebpf_program_detach_links(_Inout_ ebpf_program_t* program)
{
@ -70,6 +78,7 @@ _ebpf_program_program_info_provider_changed(
{
ebpf_result_t return_value;
ebpf_program_t* program = (ebpf_program_t*)client_binding_context;
uint32_t* provider_helper_function_ids = NULL;
if (provider_data == NULL) {
// Extension is detaching. Program will get invalidated.
@ -85,31 +94,63 @@ _ebpf_program_program_info_provider_changed(
helper_function_addresses = program_data->helper_function_addresses;
if ((program->helper_function_count > 0) &&
(helper_function_addresses->helper_function_count != program->helper_function_count))
if ((program->provider_helper_function_count > 0) &&
(helper_function_addresses->helper_function_count != program->provider_helper_function_count))
// A program info provider cannot modify helper function count upon reload.
goto Exit;
if (helper_function_addresses != NULL) {
ebpf_program_info_t* program_info = program_data->program_info;
ebpf_helper_function_prototype_t* helper_prototypes = NULL;
ebpf_assert(program_info != NULL);
if (program_info->count_of_helpers != helper_function_addresses->helper_function_count) {
return_value = EBPF_INVALID_ARGUMENT;
goto Exit;
}
helper_prototypes = program_info->helper_prototype;
if (helper_prototypes == NULL) {
return_value = EBPF_INVALID_ARGUMENT;
goto Exit;
}
if (!program->trampoline_table) {
// Program info provider is being loaded for the first time. Allocate trampoline table.
program->helper_function_count = helper_function_addresses->helper_function_count;
program->provider_helper_function_count = helper_function_addresses->helper_function_count;
return_value =
ebpf_allocate_trampoline_table(program->helper_function_count, &program->trampoline_table);
ebpf_allocate_trampoline_table(program->provider_helper_function_count, &program->trampoline_table);
if (return_value != EBPF_SUCCESS)
goto Exit;
}
_Analysis_assume_(program->provider_helper_function_count > 0);
provider_helper_function_ids =
(uint32_t*)ebpf_allocate(sizeof(uint32_t) * program->provider_helper_function_count);
if (provider_helper_function_ids == NULL) {
return_value = EBPF_NO_MEMORY;
goto Exit;
}
for (uint32_t index = 0; index < program->provider_helper_function_count; index++)
provider_helper_function_ids[index] = helper_prototypes[index].helper_id;
// Update trampoline table with new helper function addresses.
return_value = ebpf_update_trampoline_table(program->trampoline_table, helper_function_addresses);
return_value = ebpf_update_trampoline_table(
program->trampoline_table,
program->provider_helper_function_count,
provider_helper_function_ids,
helper_function_addresses);
if (return_value != EBPF_SUCCESS)
goto Exit;
if (program->code_or_vm.vm != NULL) {
// Register with uBPF for interpreted mode.
return_value = _ebpf_program_register_helpers(program);
if (return_value != EBPF_SUCCESS)
goto Exit;
}
}
}
program->program_info_binding_context = provider_binding_context;
program->program_info_provider_data = provider_data;
Exit:
ebpf_free(provider_helper_function_ids);
program->program_invalidated = (program->program_info_provider_data == NULL);
}
@ -174,6 +215,8 @@ _ebpf_program_epoch_free(void* context)
ebpf_free_trampoline_table(program->trampoline_table);
ebpf_free(program->helper_function_ids);
ebpf_free(program->cleanup_work_item);
ebpf_free(program);
}
@ -359,14 +402,15 @@ ebpf_program_associate_maps(ebpf_program_t* program, ebpf_map_t** maps, size_t m
return EBPF_SUCCESS;
}
ebpf_result_t
ebpf_program_load_machine_code(ebpf_program_t* program, uint8_t* machine_code, size_t machine_code_size)
static ebpf_result_t
_ebpf_program_load_machine_code(
_Inout_ ebpf_program_t* program, _In_ const uint8_t* machine_code, size_t machine_code_size)
{
ebpf_result_t return_value;
uint8_t* local_machine_code = NULL;
ebpf_memory_descriptor_t* local_code_memory_descriptor = NULL;
if (program->parameters.code_type != EBPF_CODE_NONE) {
if (program->parameters.code_type != EBPF_CODE_NATIVE) {
return_value = EBPF_INVALID_ARGUMENT;
goto Done;
}
@ -385,7 +429,6 @@ ebpf_program_load_machine_code(ebpf_program_t* program, uint8_t* machine_code, s
goto Done;
}
program->parameters.code_type = EBPF_CODE_NATIVE;
program->code_or_vm.code.code_memory_descriptor = local_code_memory_descriptor;
program->code_or_vm.code.code_pointer = local_machine_code;
local_code_memory_descriptor = NULL;
@ -401,35 +444,59 @@ Done:
static ebpf_result_t
_ebpf_program_register_helpers(ebpf_program_t* program)
{
ebpf_result_t result = EBPF_SUCCESS;
size_t index = 0;
ebpf_program_data_t* general_helper_program_data =
(ebpf_program_data_t*)program->general_helper_provider_data->data;
ebpf_helper_function_addresses_t* general_helper_function_addresses =
general_helper_program_data->helper_function_addresses;
size_t count = general_helper_function_addresses->helper_function_count;
for (index = 0; index < count; index++) {
const void* helper = (void*)general_helper_function_addresses->helper_function_address[index];
ebpf_assert(program->code_or_vm.vm != NULL);
for (index = 0; index < program->helper_function_count; index++) {
uint32_t helper_function_id = program->helper_function_ids[index];
const void* helper = NULL;
if (helper_function_id > EBPF_MAX_GENERAL_HELPER_FUNCTION) {
// Get the program-type specific helper function address from the trampoline table.
result = ebpf_get_trampoline_helper_address(
program->trampoline_table,
(size_t)(helper_function_id - (EBPF_MAX_GENERAL_HELPER_FUNCTION + 1)),
(void**)&helper);
if (result != EBPF_SUCCESS)
goto Exit;
} else {
// Get the general helper function address.
if (helper_function_id > general_helper_function_addresses->helper_function_count) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
helper = (void*)general_helper_function_addresses->helper_function_address[helper_function_id];
}
if (helper == NULL)
continue;
if (ubpf_register(program->code_or_vm.vm, (unsigned int)index, NULL, (void*)helper) < 0)
return EBPF_INVALID_ARGUMENT;
if (ubpf_register(program->code_or_vm.vm, (unsigned int)index, NULL, (void*)helper) < 0) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
}
return EBPF_SUCCESS;
Exit:
return result;
}
ebpf_result_t
ebpf_program_load_byte_code(ebpf_program_t* program, ebpf_instruction_t* instructions, size_t instruction_count)
static ebpf_result_t
_ebpf_program_load_byte_code(
_Inout_ ebpf_program_t* program, _In_ const ebpf_instruction_t* instructions, size_t instruction_count)
{
ebpf_result_t return_value;
char* error_message = NULL;
if (program->parameters.code_type != EBPF_CODE_NONE) {
if (program->parameters.code_type != EBPF_CODE_EBPF) {
return_value = EBPF_INVALID_ARGUMENT;
goto Done;
}
program->parameters.code_type = EBPF_CODE_EBPF;
program->code_or_vm.vm = ubpf_create();
if (!program->code_or_vm.vm) {
return_value = EBPF_NO_MEMORY;
@ -465,6 +532,22 @@ Done:
return return_value;
}
ebpf_result_t
ebpf_program_load_code(
_Inout_ ebpf_program_t* program, ebpf_code_type_t code_type, _In_ const uint8_t* code, size_t code_size)
{
ebpf_result_t result = EBPF_SUCCESS;
program->parameters.code_type = code_type;
if (program->parameters.code_type == EBPF_CODE_NATIVE)
result = _ebpf_program_load_machine_code(program, code, code_size);
else if (program->parameters.code_type == EBPF_CODE_EBPF)
result = _ebpf_program_load_byte_code(
program, (const ebpf_instruction_t*)code, code_size / sizeof(ebpf_instruction_t));
else
result = EBPF_INVALID_ARGUMENT;
return result;
}
void
ebpf_program_invoke(_In_ const ebpf_program_t* program, _In_ void* context, _Out_ uint32_t* result)
{
@ -488,8 +571,8 @@ ebpf_program_invoke(_In_ const ebpf_program_t* program, _In_ void* context, _Out
}
}
ebpf_result_t
ebpf_program_get_helper_function_address(
static ebpf_result_t
_ebpf_program_get_helper_function_address(
_In_ const ebpf_program_t* program, const uint32_t helper_function_id, uint64_t* address)
{
if (helper_function_id > EBPF_MAX_GENERAL_HELPER_FUNCTION) {
@ -520,6 +603,59 @@ ebpf_program_get_helper_function_address(
return EBPF_SUCCESS;
}
ebpf_result_t
ebpf_program_get_helper_function_addresses(
_In_ const ebpf_program_t* program, size_t addresses_count, _Out_writes_(addresses_count) uint64_t* addresses)
{
ebpf_result_t result = EBPF_SUCCESS;
if (program->helper_function_count > addresses_count) {
result = EBPF_INSUFFICIENT_BUFFER;
goto Exit;
}
for (uint32_t index = 0; index < program->helper_function_count; index++) {
result =
_ebpf_program_get_helper_function_address(program, program->helper_function_ids[index], &addresses[index]);
if (result != EBPF_SUCCESS)
break;
}
Exit:
return result;
}
ebpf_result_t
ebpf_program_set_helper_function_ids(
_Inout_ ebpf_program_t* program,
const size_t helper_function_count,
_In_reads_(helper_function_count) const uint32_t* helper_function_ids)
{
ebpf_result_t result = EBPF_SUCCESS;
if (program->helper_function_ids != NULL) {
// Helper function IDs already set.
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
if (helper_function_count == 0)
goto Exit;
program->helper_function_count = helper_function_count;
program->helper_function_ids = ebpf_allocate(sizeof(uint32_t) * helper_function_count);
if (program->helper_function_ids == NULL) {
result = EBPF_NO_MEMORY;
goto Exit;
}
for (size_t index = 0; index < helper_function_count; index++)
program->helper_function_ids[index] = helper_function_ids[index];
Exit:
return result;
}
ebpf_result_t
ebpf_program_get_program_info(_In_ const ebpf_program_t* program, _Outptr_ ebpf_program_info_t** program_info)
{

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

@ -109,31 +109,20 @@ extern "C"
ebpf_program_associate_maps(ebpf_program_t* program, ebpf_map_t** maps, size_t maps_count);
/**
* @brief Load a block of machine code into the program instance.
* @brief Load a block of eBPF code into the program instance.
*
* @param[in] program Program instance to load the machine code into.
* @param[in] machine_code Pointer to memory containing the machine code.
* @param[in] machine_code_size Size of the memory block containing the machine
* @param[in, out] program Program instance to load the eBPF code into.
* @param[in] code_type Specifies whether eBPF code is JIT compiled or byte code.
* @param[in] code Pointer to memory containing the eBPF code.
* @param[in] machine_size Size of the memory block containing the eBPF
* code.
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
* program instance.
*/
ebpf_result_t
ebpf_program_load_machine_code(ebpf_program_t* program, uint8_t* machine_code, size_t machine_code_size);
/**
* @brief Load a block of eBPF instructions into the program instance.
*
* @param[in] program Program instance to load the byte code into.
* @param[in] instructions Pointer to array of eBPF instructions.
* @param[in] instruction_count Count of eBPF instructions to load.
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
* program instance.
*/
ebpf_result_t
ebpf_program_load_byte_code(ebpf_program_t* program, ebpf_instruction_t* instructions, size_t instruction_count);
ebpf_program_load_code(
_Inout_ ebpf_program_t* program, ebpf_code_type_t code_type, _In_ const uint8_t* code, size_t code_size);
/**
* @brief Invoke an ebpf_program_t instance.
@ -146,17 +135,39 @@ extern "C"
ebpf_program_invoke(_In_ const ebpf_program_t* program, _In_ void* context, _Out_ uint32_t* result);
/**
* @brief Get the address of a helper function.
* @brief Store the helper function IDs that are used by the eBPF program in an array
* inside the program object. The array index is the helper function ID to be used by
* uBPF whereas the array value is the actual helper ID.
*
* @param[in] program Program object to query this on.
* @param[in] helper_function_id Helper function ID to look up.
* @param[out] address Address of the helper function.
* @param[in, out] program Program object to query this on.
* @param[in] helper_function_count Count of helper functions.
* @param[in] helper_function_ids Array of helper function IDs to store.
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_ARGUMENT The helper_function_id is not valid.
* @retval EBPF_INVALID_ARGUMENT The helper function IDs array is already populated.
* @retval EBPF_NO_MEMORY Could not allocate array of helper function IDs.
*/
ebpf_result_t
ebpf_program_get_helper_function_address(
_In_ const ebpf_program_t* program, const uint32_t helper_function_id, uint64_t* address);
ebpf_program_set_helper_function_ids(
_Inout_ ebpf_program_t* program,
const size_t helper_function_count,
_In_reads_(helper_function_count) const uint32_t* helper_function_ids);
/**
* @brief Get the address of a helper functions referred to by the program. Assumes
* ebpf_program_set_helper_function_ids has already been invoked on the program object.
*
* @param[in] program Program object to query this on.
* @param[in] addresses_count Length of caller supplied output array.
* @param[out] address Caller supplied output array where the addresses of the helper functions are written to.
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INSUFFICIENT_BUFFER Output array is insufficient.
* @retval EBPF_INVALID_ARGUMENT At least one helper function id is not valid.
*/
ebpf_result_t
ebpf_program_get_helper_function_addresses(
_In_ const ebpf_program_t* program,
const size_t addresses_count,
_Out_writes_(addresses_count) uint64_t* addresses);
/**
* @brief Attach a link object to an eBPF program.

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

@ -125,6 +125,7 @@ TEST_CASE("map_crud_operations_hash_per_cpu", "[execution_context]")
}
#define TEST_FUNCTION_RETURN 42
#define TOTAL_HELPER_COUNT 3
uint32_t
test_function()
@ -179,29 +180,35 @@ TEST_CASE("program", "[execution_context]")
ebpf_result_t (*test_function)();
auto provider_function1 = []() { return (ebpf_result_t)TEST_FUNCTION_RETURN; };
ebpf_result_t (*function_pointer1)() = provider_function1;
uint32_t test_function_ids[] = {(EBPF_MAX_GENERAL_HELPER_FUNCTION + 1)};
const void* helper_functions[] = {(void*)function_pointer1};
ebpf_helper_function_addresses_t helper_function_addresses = {
EBPF_COUNT_OF(helper_functions), (uint64_t*)helper_functions};
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, &helper_function_addresses) == EBPF_SUCCESS);
REQUIRE(
ebpf_update_trampoline_table(
table, EBPF_COUNT_OF(test_function_ids), test_function_ids, &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.
REQUIRE(
ebpf_program_load_machine_code(program.get(), reinterpret_cast<uint8_t*>(test_function), PAGE_SIZE) ==
ebpf_program_load_code(program.get(), EBPF_CODE_NATIVE, reinterpret_cast<uint8_t*>(test_function), PAGE_SIZE) ==
EBPF_SUCCESS);
uint32_t result = 0;
bind_md_t ctx{0};
ebpf_program_invoke(program.get(), &ctx, &result);
REQUIRE(result == TEST_FUNCTION_RETURN);
uint64_t address = 0;
REQUIRE(ebpf_program_get_helper_function_address(program.get(), 1, &address) == EBPF_SUCCESS);
REQUIRE(address != 0);
REQUIRE(ebpf_program_get_helper_function_address(program.get(), 0, &address) == EBPF_SUCCESS);
REQUIRE(address == 0);
REQUIRE(ebpf_program_get_helper_function_address(program.get(), 0xFFFF, &address) == EBPF_INVALID_ARGUMENT);
REQUIRE(address == 0);
ebpf_free_trampoline_table(table);
uint64_t addresses[TOTAL_HELPER_COUNT] = {};
uint32_t helper_function_ids[] = {1, 0, 2};
REQUIRE(
ebpf_program_set_helper_function_ids(program.get(), EBPF_COUNT_OF(helper_function_ids), helper_function_ids) ==
EBPF_SUCCESS);
REQUIRE(
ebpf_program_get_helper_function_addresses(program.get(), EBPF_COUNT_OF(helper_function_ids), addresses) ==
EBPF_SUCCESS);
REQUIRE(addresses[0] != 0);
REQUIRE(addresses[1] == 0);
REQUIRE(addresses[2] != 0);
}

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

@ -698,14 +698,19 @@ extern "C"
* @brief Populate the function pointers in a trampoline table.
*
* @param[in] trampoline_table Trampoline table to populate.
* @param[in] helper_function_count Count of helper functions.
* @param[in] helper_function_ids Array of helper function IDs.
* @param[in] dispatch_table Dispatch table to populate from.
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
* operation.
* @retval EBPF_INVALID_ARGUMENT An invalid argument was supplied.
*/
ebpf_result_t
ebpf_update_trampoline_table(
_Inout_ ebpf_trampoline_table_t* trampoline_table,
uint32_t helper_function_count,
_In_reads_(helper_function_count) const uint32_t* helper_function_ids,
_In_ const ebpf_helper_function_addresses_t* helper_function_addresses);
/**
@ -723,6 +728,21 @@ extern "C"
ebpf_get_trampoline_function(
_In_ const ebpf_trampoline_table_t* trampoline_table, size_t index, _Out_ void** function);
/**
* @brief Get the address of the helper function from the trampoline table entry.
*
* @param[in] trampoline_table Trampoline table to query.
* @param[in] index Index of trampoline table entry.
* @param[out] helper_address Pointer to memory that contains the address to helper function on success.
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
* operation.
* @retval EBPF_INVALID_ARGUMENT An invalid argument was supplied.
*/
ebpf_result_t
ebpf_get_trampoline_helper_address(
_In_ const ebpf_trampoline_table_t* trampoline_table, size_t index, _Out_ void** helper_address);
typedef struct _ebpf_program_info ebpf_program_info_t;
/**

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

@ -63,6 +63,8 @@ ebpf_free_trampoline_table(_Frees_ptr_opt_ ebpf_trampoline_table_t* trampoline_t
ebpf_result_t
ebpf_update_trampoline_table(
_Inout_ ebpf_trampoline_table_t* trampoline_table,
uint32_t helper_function_count,
_In_reads_(helper_function_count) const uint32_t* helper_function_ids,
_In_ const ebpf_helper_function_addresses_t* helper_function_addresses)
{
#if defined(_AMD64_)
@ -70,6 +72,8 @@ ebpf_update_trampoline_table(
size_t function_count = helper_function_addresses->helper_function_count;
ebpf_trampoline_entry_t* local_entries;
ebpf_result_t return_value;
size_t index;
uint32_t helper_index;
if (function_count != trampoline_table->entry_count) {
return_value = EBPF_INVALID_ARGUMENT;
@ -88,12 +92,18 @@ ebpf_update_trampoline_table(
goto Exit;
}
size_t index;
for (index = 0; index < trampoline_table->entry_count; index++) {
for (helper_index = 0; helper_index < helper_function_count; helper_index++) {
ebpf_assert(helper_function_ids[helper_index] > EBPF_MAX_GENERAL_HELPER_FUNCTION);
_Analysis_assume_(helper_function_ids[helper_index] > EBPF_MAX_GENERAL_HELPER_FUNCTION);
index = helper_function_ids[helper_index] - (EBPF_MAX_GENERAL_HELPER_FUNCTION + 1);
if (index > trampoline_table->entry_count) {
return_value = EBPF_INVALID_ARGUMENT;
goto Exit;
}
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*)helper_function_addresses->helper_function_address[index];
local_entries[index].address = (void*)helper_function_addresses->helper_function_address[helper_index];
}
Exit:
@ -130,3 +140,29 @@ ebpf_get_trampoline_function(_In_ const ebpf_trampoline_table_t* trampoline_tabl
Exit:
return return_value;
}
ebpf_result_t
ebpf_get_trampoline_helper_address(
_In_ const ebpf_trampoline_table_t* trampoline_table, size_t index, _Out_ void** helper_address)
{
ebpf_trampoline_entry_t* local_entries;
ebpf_result_t return_value;
if (index >= trampoline_table->entry_count) {
return_value = EBPF_INVALID_ARGUMENT;
goto Exit;
}
local_entries =
(ebpf_trampoline_entry_t*)ebpf_memory_descriptor_get_base_address(trampoline_table->memory_descriptor);
if (!local_entries) {
return_value = EBPF_NO_MEMORY;
goto Exit;
}
*helper_address = local_entries[index].address;
return_value = EBPF_SUCCESS;
Exit:
return return_value;
}

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

@ -331,6 +331,7 @@ TEST_CASE("trampoline_test", "[platform]")
auto provider_function1 = []() { return EBPF_SUCCESS; };
ebpf_result_t (*function_pointer1)() = provider_function1;
const void* helper_functions1[] = {(void*)function_pointer1};
const uint32_t provider_helper_function_ids[] = {(uint32_t)(EBPF_MAX_GENERAL_HELPER_FUNCTION + 1)};
ebpf_helper_function_addresses_t helper_function_addresses1 = {
EBPF_COUNT_OF(helper_functions1), (uint64_t*)helper_functions1};
@ -341,13 +342,23 @@ TEST_CASE("trampoline_test", "[platform]")
EBPF_COUNT_OF(helper_functions1), (uint64_t*)helper_functions2};
REQUIRE(ebpf_allocate_trampoline_table(1, &table) == EBPF_SUCCESS);
REQUIRE(ebpf_update_trampoline_table(table, &helper_function_addresses1) == EBPF_SUCCESS);
REQUIRE(
ebpf_update_trampoline_table(
table,
EBPF_COUNT_OF(provider_helper_function_ids),
provider_helper_function_ids,
&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, &helper_function_addresses2) == EBPF_SUCCESS);
REQUIRE(
ebpf_update_trampoline_table(
table,
EBPF_COUNT_OF(provider_helper_function_ids),
provider_helper_function_ids,
&helper_function_addresses2) == EBPF_SUCCESS);
// Verify that the trampoline function now invokes the new provider function
REQUIRE(test_function() == EBPF_OBJECT_ALREADY_EXISTS);

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

@ -334,11 +334,12 @@ ebpf_verify_and_load_program(
goto Exit;
}
std::vector<uint64_t> helper_id_adddress;
result = _build_helper_id_to_address_map(program_handle, byte_code_buffer, helper_id_adddress);
if (result != EBPF_SUCCESS)
goto Exit;
if (execution_type == EBPF_EXECUTION_JIT) {
std::vector<uint64_t> helper_id_adddress;
result = _build_helper_id_to_address_map(program_handle, byte_code_buffer, helper_id_adddress);
if (result != EBPF_SUCCESS)
goto Exit;
ebpf_code_buffer_t machine_code(MAX_CODE_SIZE_IN_BYTES);
size_t machine_code_size = machine_code.size();

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

@ -49,7 +49,8 @@ _program_load_helper(
return result;
}
TEST_CASE("test_test", "[test_test]")
void
sample_ebpf_ext_test(ebpf_execution_type_t execution_type)
{
ebpf_result_t result;
struct bpf_object* object = nullptr;
@ -70,7 +71,7 @@ TEST_CASE("test_test", "[test_test]")
REQUIRE(ebpf_api_initiate() == EBPF_SUCCESS);
result =
_program_load_helper("test_sample_ebpf.o", &EBPF_PROGRAM_TYPE_SAMPLE, EBPF_EXECUTION_JIT, &object, &program_fd);
_program_load_helper("test_sample_ebpf.o", &EBPF_PROGRAM_TYPE_SAMPLE, execution_type, &object, &program_fd);
REQUIRE(result == EBPF_SUCCESS);
REQUIRE(program_fd > 0);
@ -129,3 +130,7 @@ TEST_CASE("test_test", "[test_test]")
ebpf_api_terminate();
}
TEST_CASE("jit_test", "[test_test]") { sample_ebpf_ext_test(EBPF_EXECUTION_JIT); }
TEST_CASE("interpret_test", "[test_test]") { sample_ebpf_ext_test(EBPF_EXECUTION_INTERPRET); }