diff --git a/libs/execution_context/ebpf_core.c b/libs/execution_context/ebpf_core.c index 4f7a056ec..092abc5aa 100644 --- a/libs/execution_context/ebpf_core.c +++ b/libs/execution_context/ebpf_core.c @@ -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) { diff --git a/libs/execution_context/ebpf_program.c b/libs/execution_context/ebpf_program.c index 402cc0044..b205b1488 100644 --- a/libs/execution_context/ebpf_program.c +++ b/libs/execution_context/ebpf_program.c @@ -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) { diff --git a/libs/execution_context/ebpf_program.h b/libs/execution_context/ebpf_program.h index 1ea0be420..0a9b65254 100644 --- a/libs/execution_context/ebpf_program.h +++ b/libs/execution_context/ebpf_program.h @@ -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. diff --git a/libs/execution_context/unit/execution_context_unit_test.cpp b/libs/execution_context/unit/execution_context_unit_test.cpp index ca0285a84..eddca092b 100644 --- a/libs/execution_context/unit/execution_context_unit_test.cpp +++ b/libs/execution_context/unit/execution_context_unit_test.cpp @@ -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(&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(test_function), PAGE_SIZE) == + ebpf_program_load_code(program.get(), EBPF_CODE_NATIVE, reinterpret_cast(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); } diff --git a/libs/platform/ebpf_platform.h b/libs/platform/ebpf_platform.h index 7e90c1ffe..bd5cc8872 100644 --- a/libs/platform/ebpf_platform.h +++ b/libs/platform/ebpf_platform.h @@ -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; /** diff --git a/libs/platform/ebpf_trampoline.c b/libs/platform/ebpf_trampoline.c index f680d7062..f7c7787e1 100644 --- a/libs/platform/ebpf_trampoline.c +++ b/libs/platform/ebpf_trampoline.c @@ -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; +} diff --git a/libs/platform/unit/platform_unit_test.cpp b/libs/platform/unit/platform_unit_test.cpp index 57072321d..58dc785e4 100644 --- a/libs/platform/unit/platform_unit_test.cpp +++ b/libs/platform/unit/platform_unit_test.cpp @@ -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(&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); diff --git a/libs/service/api_service.cpp b/libs/service/api_service.cpp index 16d1ed089..512f56024 100644 --- a/libs/service/api_service.cpp +++ b/libs/service/api_service.cpp @@ -334,11 +334,12 @@ ebpf_verify_and_load_program( goto Exit; } + std::vector 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 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(); diff --git a/tests/sample/ext/app/sample_ext_app.cpp b/tests/sample/ext/app/sample_ext_app.cpp index 8feb9a6c5..7082f449d 100644 --- a/tests/sample/ext/app/sample_ext_app.cpp +++ b/tests/sample/ext/app/sample_ext_app.cpp @@ -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); } \ No newline at end of file