Enable leak_detection for "fault_injection" test case. (#2192)

* fix leaks

* update cicd

* fix tests

* fix

* fix

* fix

* add sal
This commit is contained in:
Anurag Saxena 2023-03-17 08:52:39 -07:00 коммит произвёл GitHub
Родитель 282134fc34
Коммит aec1c4060c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 306 добавлений и 183 удалений

2
.github/workflows/cicd.yml поставляемый
Просмотреть файл

@ -363,6 +363,7 @@ jobs:
code_coverage: true
gather_dumps: true
fault_injection: true
leak_detection: true
# Run the low memory simulator for netebpfext_unit tests.
fault_injection_netebpfext_unit:
@ -402,6 +403,7 @@ jobs:
code_coverage: false
gather_dumps: true
fault_injection: true
leak_detection: true
# Run the complete fault injection simulator for netebpfext in GitHub.
# Runs on a schedule as this takes a long time to run.

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

@ -391,11 +391,12 @@ ebpf_api_elf_enumerate_sections(
*infos = nullptr;
*error_message = nullptr;
ebpf_section_info_t* info = nullptr;
try {
auto raw_programs = read_elf(file, section ? std::string(section) : std::string(), &verifier_options, platform);
for (const auto& raw_program : raw_programs) {
ebpf_section_info_t* info = (ebpf_section_info_t*)ebpf_allocate(sizeof(*info));
info = (ebpf_section_info_t*)ebpf_allocate(sizeof(*info));
if (info == nullptr) {
throw std::runtime_error("Out of memory");
}
@ -418,24 +419,29 @@ ebpf_api_elf_enumerate_sections(
}
info->section_name = ebpf_duplicate_string(raw_program.section.c_str());
if (info->section_name == nullptr) {
throw std::runtime_error("Out of memory");
}
info->program_type_name = ebpf_duplicate_string(raw_program.info.type.name.c_str());
if (info->program_type_name == nullptr) {
throw std::runtime_error("Out of memory");
}
std::vector<uint8_t> raw_data = convert_ebpf_program_to_bytes(raw_program.prog);
info->raw_data_size = raw_data.size();
info->raw_data = (char*)ebpf_allocate(info->raw_data_size);
if (info->raw_data == nullptr || info->section_name == nullptr || info->program_type_name == nullptr) {
ebpf_free((void*)info->section_name);
ebpf_free((void*)info->program_type_name);
ebpf_free((void*)info->raw_data);
ebpf_free(info);
if (info->raw_data == nullptr) {
throw std::runtime_error("Out of memory");
}
memcpy(info->raw_data, raw_data.data(), info->raw_data_size);
info->next = *infos;
*infos = info;
info = nullptr;
}
} catch (std::runtime_error e) {
ebpf_free_sections(*infos);
ebpf_free_sections(info);
str << "error: " << e.what();
*error_message = allocate_string(str.str());
return 1;

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

@ -15,6 +15,19 @@
#define PAGE_SIZE 4096
typedef struct _free_trampoline_table
{
void
operator()(_In_opt_ _Post_invalid_ ebpf_trampoline_table_t* table)
{
if (table != nullptr) {
ebpf_free_trampoline_table(table);
}
}
} free_trampoline_table_t;
typedef std::unique_ptr<ebpf_trampoline_table_t, free_trampoline_table_t> ebpf_trampoline_table_ptr;
typedef class _ebpf_async_wrapper
{
public:
@ -680,7 +693,7 @@ TEST_CASE("program", "[execution_context]")
REQUIRE(ebpf_program_associate_maps(program.get(), maps, EBPF_COUNT_OF(maps)) == EBPF_SUCCESS);
REQUIRE(((ebpf_core_object_t*)map.get())->base.reference_count == 2);
ebpf_trampoline_table_t* table = NULL;
ebpf_trampoline_table_ptr table;
ebpf_result_t (*test_function)();
auto provider_function1 = []() { return (ebpf_result_t)TEST_FUNCTION_RETURN; };
ebpf_result_t (*function_pointer1)() = provider_function1;
@ -689,13 +702,19 @@ TEST_CASE("program", "[execution_context]")
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);
{
ebpf_trampoline_table_t* local_table = nullptr;
REQUIRE(ebpf_allocate_trampoline_table(1, &local_table) == EBPF_SUCCESS);
table.reset(local_table);
}
REQUIRE(
ebpf_update_trampoline_table(
table, EBPF_COUNT_OF(test_function_ids), test_function_ids, &helper_function_addresses) == EBPF_SUCCESS);
table.get(), EBPF_COUNT_OF(test_function_ids), test_function_ids, &helper_function_addresses) ==
EBPF_SUCCESS);
REQUIRE(
ebpf_get_trampoline_function(
table, EBPF_MAX_GENERAL_HELPER_FUNCTION + 1, reinterpret_cast<void**>(&test_function)) == EBPF_SUCCESS);
table.get(), EBPF_MAX_GENERAL_HELPER_FUNCTION + 1, reinterpret_cast<void**>(&test_function)) ==
EBPF_SUCCESS);
// Size of the actual function is unknown, but we know the allocation is on page granularity.
REQUIRE(
@ -800,7 +819,7 @@ TEST_CASE("program", "[execution_context]")
link.reset();
ebpf_free_trampoline_table(table);
ebpf_free_trampoline_table(table.release());
}
TEST_CASE("name size", "[execution_context]")

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

@ -13,6 +13,7 @@
#include "ebpf_ring_buffer.h"
#include "ebpf_serialize.h"
#include "ebpf_state.h"
#include "helpers.h"
#include <winsock2.h>
#include <Windows.h>
@ -25,6 +26,19 @@
extern ebpf_helper_function_prototype_t* ebpf_core_helper_function_prototype;
extern uint32_t ebpf_core_helper_functions_count;
typedef struct _free_ebpf_pinning_table
{
void
operator()(_In_opt_ _Post_invalid_ ebpf_pinning_table_t* table)
{
if (table != nullptr) {
ebpf_pinning_table_free(table);
}
}
} free_ebpf_pinning_table_t;
typedef std::unique_ptr<ebpf_pinning_table_t, free_ebpf_pinning_table_t> ebpf_pinning_table_ptr;
class _test_helper
{
public:
@ -276,21 +290,25 @@ TEST_CASE("pinning_test", "[platform]")
ebpf_object_initialize(
&another_object.object, EBPF_OBJECT_MAP, [](ebpf_core_object_t*) {}, NULL) == EBPF_SUCCESS);
ebpf_pinning_table_t* pinning_table = nullptr;
REQUIRE(ebpf_pinning_table_allocate(&pinning_table) == EBPF_SUCCESS);
ebpf_pinning_table_ptr pinning_table;
{
ebpf_pinning_table_t* local_pinning_table = nullptr;
REQUIRE(ebpf_pinning_table_allocate(&local_pinning_table) == EBPF_SUCCESS);
pinning_table.reset(local_pinning_table);
}
REQUIRE(ebpf_pinning_table_insert(pinning_table, &foo, &an_object.object) == EBPF_SUCCESS);
REQUIRE(ebpf_pinning_table_insert(pinning_table.get(), &foo, &an_object.object) == EBPF_SUCCESS);
REQUIRE(an_object.object.base.reference_count == 2);
REQUIRE(ebpf_pinning_table_insert(pinning_table, &bar, &another_object.object) == EBPF_SUCCESS);
REQUIRE(ebpf_pinning_table_insert(pinning_table.get(), &bar, &another_object.object) == EBPF_SUCCESS);
REQUIRE(another_object.object.base.reference_count == 2);
REQUIRE(ebpf_pinning_table_find(pinning_table, &foo, (ebpf_core_object_t**)&some_object) == EBPF_SUCCESS);
REQUIRE(ebpf_pinning_table_find(pinning_table.get(), &foo, (ebpf_core_object_t**)&some_object) == EBPF_SUCCESS);
REQUIRE(an_object.object.base.reference_count == 3);
REQUIRE(some_object == &an_object);
ebpf_object_release_reference(&some_object->object);
REQUIRE(ebpf_pinning_table_delete(pinning_table, &foo) == EBPF_SUCCESS);
REQUIRE(ebpf_pinning_table_delete(pinning_table.get(), &foo) == EBPF_SUCCESS);
REQUIRE(another_object.object.base.reference_count == 2);
ebpf_pinning_table_free(pinning_table);
ebpf_pinning_table_free(pinning_table.release());
REQUIRE(an_object.object.base.reference_count == 1);
REQUIRE(another_object.object.base.reference_count == 1);
@ -457,6 +475,7 @@ TEST_CASE("extension_test", "[platform]")
ebpf_extension_data_t client_data{};
ebpf_extension_data_t provider_data{};
GUID interface_id;
ebpf_result_t result;
const ebpf_extension_dispatch_table_t* returned_provider_dispatch_table;
const ebpf_extension_data_t* returned_provider_data;
@ -485,8 +504,7 @@ TEST_CASE("extension_test", "[platform]")
(NPI_PROVIDER_DETACH_CLIENT_FN*)test_provider_detach_client,
nullptr) == EBPF_SUCCESS);
REQUIRE(
ebpf_extension_load(
result = ebpf_extension_load(
&client_context,
&interface_id,
&provider_module_id,
@ -497,13 +515,20 @@ TEST_CASE("extension_test", "[platform]")
&provider_binding_context,
&returned_provider_data,
&returned_provider_dispatch_table,
nullptr) == EBPF_SUCCESS);
nullptr);
if (result != EBPF_SUCCESS) {
ebpf_provider_unload(provider_context);
}
REQUIRE(result == EBPF_SUCCESS);
REQUIRE(returned_provider_data == &provider_data);
REQUIRE(returned_provider_dispatch_table == &test_provider_dispatch_table);
ebpf_extension_unload(client_context);
#pragma warning(push)
#pragma warning(disable : 6001) // Using uninitialized memory 'provider_context'.
ebpf_provider_unload(provider_context);
#pragma warning(pop)
}
TEST_CASE("trampoline_test", "[platform]")
@ -619,10 +644,10 @@ TEST_CASE("serialize_map_test", "[platform]")
std::string pin_path_prefix = "\\ebpf\\map\\";
std::vector<std::string> pin_paths;
size_t buffer_length = 0;
uint8_t* buffer = nullptr;
size_t required_length;
size_t serialized_length;
ebpf_map_info_t* map_info_array;
ebpf_memory_t unique_buffer;
// Construct the array of ebpf_map_info_internal_t to be serialized.
for (int i = 0; i < map_count; i++) {
@ -643,24 +668,31 @@ TEST_CASE("serialize_map_test", "[platform]")
// Serialize.
REQUIRE(
ebpf_serialize_internal_map_info_array(
map_count, internal_map_info_array, buffer, buffer_length, &serialized_length, &required_length) ==
map_count, internal_map_info_array, nullptr, buffer_length, &serialized_length, &required_length) ==
EBPF_INSUFFICIENT_BUFFER);
buffer = static_cast<uint8_t*>(ebpf_allocate(required_length));
// Required to deal with code analysis warning about buffer not being checked for null.
{
uint8_t* buffer = static_cast<uint8_t*>(ebpf_allocate(required_length));
if (buffer == nullptr) {
REQUIRE(false);
return;
}
unique_buffer.reset(buffer);
}
buffer_length = required_length;
REQUIRE(
ebpf_serialize_internal_map_info_array(
map_count, internal_map_info_array, buffer, buffer_length, &serialized_length, &required_length) ==
EBPF_SUCCESS);
map_count,
internal_map_info_array,
unique_buffer.get(),
buffer_length,
&serialized_length,
&required_length) == EBPF_SUCCESS);
// Deserialize.
REQUIRE(ebpf_deserialize_map_info_array(serialized_length, buffer, map_count, &map_info_array) == EBPF_SUCCESS);
REQUIRE(
ebpf_deserialize_map_info_array(serialized_length, unique_buffer.get(), map_count, &map_info_array) ==
EBPF_SUCCESS);
_Analysis_assume_(map_info_array != nullptr);
// Verify de-serialized map info array matches input.
for (int i = 0; i < map_count; i++) {
@ -674,8 +706,6 @@ TEST_CASE("serialize_map_test", "[platform]")
// Free de-serialized map info array.
ebpf_map_info_array_free(map_count, map_info_array);
ebpf_free(buffer);
}
TEST_CASE("serialize_program_info_test", "[platform]")
@ -699,29 +729,32 @@ TEST_CASE("serialize_program_info_test", "[platform]")
ebpf_program_info_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_memory_t unique_buffer;
ebpf_program_info_t* out_program_info;
// Serialize.
REQUIRE(ebpf_serialize_program_info(&in_program_info, buffer, buffer_length, &serialized_length, &required_length));
REQUIRE(
ebpf_serialize_program_info(&in_program_info, nullptr, buffer_length, &serialized_length, &required_length));
buffer = static_cast<uint8_t*>(ebpf_allocate(required_length));
// Work around code analysis warning about buffer not being checked for null.
{
uint8_t* buffer = static_cast<uint8_t*>(ebpf_allocate(required_length));
if (buffer == nullptr) {
REQUIRE(false);
return;
}
unique_buffer.reset(buffer);
}
buffer_length = required_length;
REQUIRE(
ebpf_serialize_program_info(&in_program_info, buffer, buffer_length, &serialized_length, &required_length) ==
ebpf_serialize_program_info(
&in_program_info, unique_buffer.get(), buffer_length, &serialized_length, &required_length) ==
EBPF_SUCCESS);
// Deserialize.
REQUIRE(ebpf_deserialize_program_info(serialized_length, buffer, &out_program_info) == EBPF_SUCCESS);
REQUIRE(ebpf_deserialize_program_info(serialized_length, unique_buffer.get(), &out_program_info) == EBPF_SUCCESS);
// Verify de-serialized program info matches input.
REQUIRE(
@ -757,8 +790,6 @@ TEST_CASE("serialize_program_info_test", "[platform]")
// Free de-serialized program info.
ebpf_program_info_free(out_program_info);
ebpf_free(buffer);
}
TEST_CASE("state_test", "[state]")

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

@ -64,6 +64,19 @@ CATCH_REGISTER_LISTENER(_passed_test_log)
extern thread_local bool ebpf_non_preemptible;
typedef struct _close_bpf_object
{
void
operator()(_In_opt_ _Post_invalid_ bpf_object* object)
{
if (object != nullptr) {
bpf_object__close(object);
}
}
} close_bpf_object_t;
typedef std::unique_ptr<bpf_object, close_bpf_object_t> bpf_object_ptr;
std::vector<uint8_t>
prepare_ip_packet(uint16_t ethernet_type)
{
@ -330,16 +343,17 @@ ebpf_program_load(
_In_z_ const char* file_name,
bpf_prog_type prog_type,
ebpf_execution_type_t execution_type,
_Outptr_result_maybenull_ struct bpf_object** object,
_Out_ bpf_object_ptr* unique_object,
_Out_ fd_t* program_fd,
_Outptr_opt_result_maybenull_z_ const char** log_buffer)
{
*object = nullptr;
*program_fd = ebpf_fd_invalid;
if (log_buffer) {
*log_buffer = nullptr;
}
unique_object->reset(nullptr);
bpf_object* new_object = bpf_object__open(file_name);
if (new_object == nullptr) {
return -errno;
@ -365,7 +379,7 @@ ebpf_program_load(
}
*program_fd = bpf_program__fd(program);
*object = new_object;
unique_object->reset(new_object);
return 0;
}
@ -376,26 +390,26 @@ droppacket_test(ebpf_execution_type_t execution_type)
int result;
const char* error_message = nullptr;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
bpf_link* link;
bpf_link_ptr link;
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "droppacket_um.dll" : "droppacket.o");
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, &error_message);
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
ebpf_free((void*)error_message);
}
REQUIRE(result == 0);
fd_t dropped_packet_map_fd = bpf_object__find_map_fd_by_name(object, "dropped_packet_map");
fd_t dropped_packet_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "dropped_packet_map");
// Tell the program which interface to filter on.
fd_t interface_index_map_fd = bpf_object__find_map_fd_by_name(object, "interface_index_map");
fd_t interface_index_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "interface_index_map");
uint32_t key = 0;
uint32_t if_index = TEST_IFINDEX;
REQUIRE(bpf_map_update_elem(interface_index_map_fd, &key, &if_index, EBPF_ANY) == EBPF_SUCCESS);
@ -436,8 +450,7 @@ droppacket_test(ebpf_execution_type_t execution_type)
REQUIRE(value == 0);
// Reattach to all interfaces so we can test the ingress_ifindex field passed to the program.
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
if_index = 0;
REQUIRE(hook.attach_link(program_fd, &if_index, sizeof(if_index), &link) == EBPF_SUCCESS);
@ -478,10 +491,9 @@ droppacket_test(ebpf_execution_type_t execution_type)
REQUIRE(bpf_map_lookup_elem(dropped_packet_map_fd, &key, &value) == EBPF_SUCCESS);
REQUIRE(value == 0);
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
// See also divide_by_zero_test_km in api_test.cpp for the kernel-mode equivalent.
@ -492,17 +504,16 @@ divide_by_zero_test_um(ebpf_execution_type_t execution_type)
int result;
const char* error_message = nullptr;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
bpf_link* link;
bpf_link_ptr link;
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "divide_by_zero_um.dll" : "divide_by_zero.o");
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, &error_message);
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
ebpf_free((void*)error_message);
@ -522,10 +533,9 @@ divide_by_zero_test_um(ebpf_execution_type_t execution_type)
REQUIRE(hook_result == 0);
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
void
@ -535,7 +545,7 @@ bad_map_name_um(ebpf_execution_type_t execution_type)
int result;
const char* error_message = nullptr;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
@ -543,7 +553,8 @@ bad_map_name_um(ebpf_execution_type_t execution_type)
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "bad_map_name_um.dll" : "bad_map_name.o");
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, &error_message);
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -551,7 +562,7 @@ bad_map_name_um(ebpf_execution_type_t execution_type)
}
REQUIRE(result == -EINVAL);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
typedef struct _process_entry
@ -638,8 +649,8 @@ bindmonitor_test(ebpf_execution_type_t execution_type)
const char* error_message = nullptr;
uint64_t fake_pid = 12345;
int result;
bpf_object* object = nullptr;
bpf_link* link = nullptr;
bpf_object_ptr unique_object;
bpf_link_ptr link;
fd_t program_fd;
uint64_t process_id = _get_current_pid_tgid();
@ -650,18 +661,19 @@ bindmonitor_test(ebpf_execution_type_t execution_type)
// bpf2c.exe tool.
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "bindmonitor_um.dll" : "bindmonitor.o");
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, &error_message);
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
ebpf_free((void*)error_message);
}
REQUIRE(result == 0);
fd_t limit_map_fd = bpf_object__find_map_fd_by_name(object, "limits_map");
fd_t limit_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "limits_map");
REQUIRE(limit_map_fd > 0);
fd_t process_map_fd = bpf_object__find_map_fd_by_name(object, "process_map");
fd_t process_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "process_map");
REQUIRE(process_map_fd > 0);
fd_t audit_map_fd = bpf_object__find_map_fd_by_name(object, "audit_map");
fd_t audit_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "audit_map");
REQUIRE(audit_map_fd > 0);
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND, EBPF_ATTACH_TYPE_BIND);
@ -717,10 +729,9 @@ bindmonitor_test(ebpf_execution_type_t execution_type)
REQUIRE(bpf_map_get_next_key(process_map_fd, &pid, &pid) < 0);
REQUIRE(errno == ENOENT);
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
void
@ -731,38 +742,39 @@ bindmonitor_tailcall_test(ebpf_execution_type_t execution_type)
const char* error_message = nullptr;
uint64_t fake_pid = 12345;
int result;
bpf_object* object = nullptr;
bpf_link* link = nullptr;
bpf_object_ptr unique_object;
bpf_link_ptr link;
fd_t program_fd;
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
const char* file_name =
(execution_type == EBPF_EXECUTION_NATIVE ? "bindmonitor_tailcall_um.dll" : "bindmonitor_tailcall.o");
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, &error_message);
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
ebpf_free((void*)error_message);
}
REQUIRE(result == 0);
fd_t limit_map_fd = bpf_object__find_map_fd_by_name(object, "limits_map");
fd_t limit_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "limits_map");
REQUIRE(limit_map_fd > 0);
fd_t process_map_fd = bpf_object__find_map_fd_by_name(object, "process_map");
fd_t process_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "process_map");
REQUIRE(process_map_fd > 0);
// Set up tail calls.
struct bpf_program* callee0 = bpf_object__find_program_by_name(object, "BindMonitor_Callee0");
struct bpf_program* callee0 = bpf_object__find_program_by_name(unique_object.get(), "BindMonitor_Callee0");
REQUIRE(callee0 != nullptr);
fd_t callee0_fd = bpf_program__fd(callee0);
REQUIRE(callee0_fd > 0);
struct bpf_program* callee1 = bpf_object__find_program_by_name(object, "BindMonitor_Callee1");
struct bpf_program* callee1 = bpf_object__find_program_by_name(unique_object.get(), "BindMonitor_Callee1");
REQUIRE(callee1 != nullptr);
fd_t callee1_fd = bpf_program__fd(callee1);
REQUIRE(callee1_fd > 0);
fd_t prog_map_fd = bpf_object__find_map_fd_by_name(object, "prog_array_map");
fd_t prog_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "prog_array_map");
REQUIRE(prog_map_fd > 0);
uint32_t index = 0;
@ -773,14 +785,14 @@ bindmonitor_tailcall_test(ebpf_execution_type_t execution_type)
// Validate various maps.
// Validate map-in-maps with "inner_id".
struct bpf_map* outer_map = bpf_object__find_map_by_name(object, "dummy_outer_map");
struct bpf_map* outer_map = bpf_object__find_map_by_name(unique_object.get(), "dummy_outer_map");
REQUIRE(outer_map != nullptr);
int outer_map_fd = bpf_map__fd(outer_map);
REQUIRE(outer_map_fd > 0);
// Validate map-in-maps with "inner_idx".
struct bpf_map* outer_idx_map = bpf_object__find_map_by_name(object, "dummy_outer_idx_map");
struct bpf_map* outer_idx_map = bpf_object__find_map_by_name(unique_object.get(), "dummy_outer_idx_map");
REQUIRE(outer_idx_map != nullptr);
int outer_idx_map_fd = bpf_map__fd(outer_idx_map);
@ -832,15 +844,14 @@ bindmonitor_tailcall_test(ebpf_execution_type_t execution_type)
REQUIRE(bpf_map_get_next_key(process_map_fd, &pid, &pid) < 0);
REQUIRE(errno == ENOENT);
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
index = 0;
REQUIRE(bpf_map_update_elem(prog_map_fd, &index, &ebpf_fd_invalid, 0) == 0);
index = 1;
REQUIRE(bpf_map_update_elem(prog_map_fd, &index, &ebpf_fd_invalid, 0) == 0);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
void
@ -850,8 +861,8 @@ bindmonitor_ring_buffer_test(ebpf_execution_type_t execution_type)
const char* error_message = nullptr;
int result;
bpf_object* object = nullptr;
bpf_link* link = nullptr;
bpf_object_ptr unique_object;
bpf_link_ptr link;
fd_t program_fd;
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
@ -860,7 +871,8 @@ bindmonitor_ring_buffer_test(ebpf_execution_type_t execution_type)
(execution_type == EBPF_EXECUTION_NATIVE ? "bindmonitor_ringbuf_um.dll" : "bindmonitor_ringbuf.o");
// Load and attach a bind eBPF program that uses a ring buffer map to notify about bind operations.
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, &error_message);
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -868,7 +880,7 @@ bindmonitor_ring_buffer_test(ebpf_execution_type_t execution_type)
}
REQUIRE(result == 0);
fd_t process_map_fd = bpf_object__find_map_fd_by_name(object, "process_map");
fd_t process_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "process_map");
REQUIRE(process_map_fd > 0);
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND, EBPF_ATTACH_TYPE_BIND);
@ -894,10 +906,9 @@ bindmonitor_ring_buffer_test(ebpf_execution_type_t execution_type)
REQUIRE(emulate_bind(invoke, fake_pid + i, fake_app_id.data()) == BIND_PERMIT);
});
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
static void
@ -930,16 +941,17 @@ map_test(ebpf_execution_type_t execution_type)
int result;
const char* error_message = nullptr;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
bpf_link* link;
bpf_link_ptr link;
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "map_um.dll" : "map.o");
result = ebpf_program_load(file_name, BPF_PROG_TYPE_XDP, execution_type, &object, &program_fd, &error_message);
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_XDP, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -958,10 +970,9 @@ map_test(ebpf_execution_type_t execution_type)
// Program should return 0 if all the map tests pass.
REQUIRE(hook_result >= 0);
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
DECLARE_ALL_TEST_CASES("droppacket", "[end_to_end]", droppacket_test);
@ -1074,14 +1085,14 @@ _cgroup_load_test(
{
int result;
const char* error_message = nullptr;
bpf_object* object = nullptr;
fd_t program_fd;
_test_helper_end_to_end test_helper;
single_instance_hook_t hook(program_type, attach_type);
program_info_provider_t program_info(program_type);
bpf_object_ptr unique_object;
result = ebpf_program_load(file, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, &error_message);
result = ebpf_program_load(file, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -1090,7 +1101,7 @@ _cgroup_load_test(
REQUIRE(result == 0);
bpf_program* program = bpf_object__find_program_by_name(object, name);
bpf_program* program = bpf_object__find_program_by_name(unique_object.get(), name);
REQUIRE(program != nullptr);
uint32_t compartment_id = 0;
@ -1101,7 +1112,7 @@ _cgroup_load_test(
REQUIRE(hook.attach(program, &compartment_id, sizeof(compartment_id)) == EBPF_SUCCESS);
REQUIRE(hook.detach(program_fd, &compartment_id, sizeof(compartment_id)) == EBPF_SUCCESS);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
static void
_cgroup_sock_addr_load_test(
@ -1197,7 +1208,7 @@ TEST_CASE("map_pinning_test", "[end_to_end]")
const char* error_message = nullptr;
int result;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
@ -1206,7 +1217,7 @@ TEST_CASE("map_pinning_test", "[end_to_end]")
SAMPLE_PATH "bindmonitor.o",
BPF_PROG_TYPE_UNSPEC,
EBPF_EXECUTION_INTERPRET,
&object,
&unique_object,
&program_fd,
&error_message);
@ -1221,11 +1232,14 @@ TEST_CASE("map_pinning_test", "[end_to_end]")
std::string process_maps_name = "bindmonitor::process_map";
std::string limit_maps_name = "bindmonitor::limits_map";
REQUIRE(bpf_object__find_map_by_name(object, "process_map") != nullptr);
REQUIRE(bpf_object__find_map_by_name(object, "limits_map") != nullptr);
REQUIRE(bpf_object__find_map_by_name(unique_object.get(), "process_map") != nullptr);
REQUIRE(bpf_object__find_map_by_name(unique_object.get(), "limits_map") != nullptr);
REQUIRE(
bpf_map__pin(bpf_object__find_map_by_name(object, "process_map"), process_maps_name.c_str()) == EBPF_SUCCESS);
REQUIRE(bpf_map__pin(bpf_object__find_map_by_name(object, "limits_map"), limit_maps_name.c_str()) == EBPF_SUCCESS);
bpf_map__pin(bpf_object__find_map_by_name(unique_object.get(), "process_map"), process_maps_name.c_str()) ==
EBPF_SUCCESS);
REQUIRE(
bpf_map__pin(bpf_object__find_map_by_name(unique_object.get(), "limits_map"), limit_maps_name.c_str()) ==
EBPF_SUCCESS);
fd_t fd = bpf_obj_get(process_maps_name.c_str());
REQUIRE(fd != ebpf_fd_invalid);
@ -1236,15 +1250,17 @@ TEST_CASE("map_pinning_test", "[end_to_end]")
Platform::_close(fd);
REQUIRE(
bpf_map__unpin(bpf_object__find_map_by_name(object, "process_map"), process_maps_name.c_str()) == EBPF_SUCCESS);
bpf_map__unpin(bpf_object__find_map_by_name(unique_object.get(), "process_map"), process_maps_name.c_str()) ==
EBPF_SUCCESS);
REQUIRE(
bpf_map__unpin(bpf_object__find_map_by_name(object, "limits_map"), limit_maps_name.c_str()) == EBPF_SUCCESS);
bpf_map__unpin(bpf_object__find_map_by_name(unique_object.get(), "limits_map"), limit_maps_name.c_str()) ==
EBPF_SUCCESS);
REQUIRE(bpf_obj_get(limit_maps_name.c_str()) == ebpf_fd_invalid);
REQUIRE(bpf_obj_get(process_maps_name.c_str()) == ebpf_fd_invalid);
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
TEST_CASE("enumerate_and_query_programs", "[end_to_end]")
@ -1257,7 +1273,7 @@ TEST_CASE("enumerate_and_query_programs", "[end_to_end]")
int result;
const char* file_name = nullptr;
const char* section_name = nullptr;
bpf_object* object[2] = {0};
bpf_object_ptr unique_object[2];
fd_t program_fds[2] = {0};
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
@ -1266,7 +1282,7 @@ TEST_CASE("enumerate_and_query_programs", "[end_to_end]")
SAMPLE_PATH "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
EBPF_EXECUTION_JIT,
&object[0],
&unique_object[0],
&program_fds[0],
&error_message);
@ -1280,7 +1296,7 @@ TEST_CASE("enumerate_and_query_programs", "[end_to_end]")
SAMPLE_PATH "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
EBPF_EXECUTION_INTERPRET,
&object[1],
&unique_object[1],
&program_fds[1],
&error_message);
@ -1322,8 +1338,8 @@ TEST_CASE("enumerate_and_query_programs", "[end_to_end]")
REQUIRE(bpf_prog_get_next_id(program_id, &next_program_id) == -ENOENT);
for (int i = 0; i < _countof(object); i++) {
bpf_object__close(object[i]);
for (int i = 0; i < _countof(unique_object); i++) {
bpf_object__close(unique_object[i].release());
}
}
@ -1345,7 +1361,7 @@ TEST_CASE("implicit_detach", "[end_to_end]")
_test_helper_end_to_end test_helper;
int result = 0;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
const char* error_message = nullptr;
bpf_link* link = nullptr;
@ -1354,7 +1370,12 @@ TEST_CASE("implicit_detach", "[end_to_end]")
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
result = ebpf_program_load(
SAMPLE_PATH "droppacket.o", BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_JIT, &object, &program_fd, &error_message);
SAMPLE_PATH "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
EBPF_EXECUTION_JIT,
&unique_object,
&program_fd,
&error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -1367,7 +1388,7 @@ TEST_CASE("implicit_detach", "[end_to_end]")
// Call bpf_object__close() which will close the program fd. That should
// detach the program from the hook and unload the program.
bpf_object__close(object);
bpf_object__close(unique_object.release());
uint32_t program_id;
REQUIRE(bpf_prog_get_next_id(0, &program_id) == -ENOENT);
@ -1390,7 +1411,7 @@ TEST_CASE("implicit_detach_2", "[end_to_end]")
_test_helper_end_to_end test_helper;
int result = 0;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
const char* error_message = nullptr;
bpf_link* link = nullptr;
@ -1399,7 +1420,12 @@ TEST_CASE("implicit_detach_2", "[end_to_end]")
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
result = ebpf_program_load(
SAMPLE_PATH "droppacket.o", BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_JIT, &object, &program_fd, &error_message);
SAMPLE_PATH "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
EBPF_EXECUTION_JIT,
&unique_object,
&program_fd,
&error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -1412,7 +1438,7 @@ TEST_CASE("implicit_detach_2", "[end_to_end]")
// Call bpf_object__close() which will close the program fd. That should
// detach the program from the hook and unload the program.
bpf_object__close(object);
bpf_object__close(unique_object.release());
uint32_t program_id;
REQUIRE(bpf_prog_get_next_id(0, &program_id) == -ENOENT);
@ -1433,9 +1459,9 @@ TEST_CASE("explicit_detach", "[end_to_end]")
_test_helper_end_to_end test_helper;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
bpf_link* link = nullptr;
bpf_link_ptr link;
int result;
const char* error_message = nullptr;
@ -1446,7 +1472,7 @@ TEST_CASE("explicit_detach", "[end_to_end]")
SAMPLE_PATH "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
EBPF_EXECUTION_INTERPRET,
&object,
&unique_object,
&program_fd,
&error_message);
@ -1462,11 +1488,10 @@ TEST_CASE("explicit_detach", "[end_to_end]")
// Detach and close link handle.
// ebpf_object_tracking_terminate() which is called when the test
// exits checks if all the objects in EC have been deleted.
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
// Close program handle.
bpf_object__close(object);
bpf_object__close(unique_object.release());
uint32_t program_id;
REQUIRE(bpf_prog_get_next_id(0, &program_id) == -ENOENT);
}
@ -1480,9 +1505,9 @@ TEST_CASE("implicit_explicit_detach", "[end_to_end]")
_test_helper_end_to_end test_helper;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
bpf_link* link = nullptr;
bpf_link_ptr link;
int result;
const char* error_message = nullptr;
@ -1493,7 +1518,7 @@ TEST_CASE("implicit_explicit_detach", "[end_to_end]")
SAMPLE_PATH "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
EBPF_EXECUTION_INTERPRET,
&object,
&unique_object,
&program_fd,
&error_message);
@ -1508,15 +1533,14 @@ TEST_CASE("implicit_explicit_detach", "[end_to_end]")
// Close program handle. That should detach the program from the hook
// and unload the program.
bpf_object__close(object);
bpf_object__close(unique_object.release());
uint32_t program_id;
REQUIRE(bpf_prog_get_next_id(0, &program_id) == -ENOENT);
// Detach and close link handle.
// ebpf_object_tracking_terminate() which is called when the test
// exits checks if all the objects in EC have been deleted.
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
}
TEST_CASE("create_map", "[end_to_end]")
@ -2094,10 +2118,11 @@ _map_reuse_invalid_test(ebpf_execution_type_t execution_type)
// Load BPF object from ELF file. Loading the program should fail as the
// map type for map pinned at "/ebpf/global/outer_map" does not match.
struct bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "map_reuse_um.dll" : "map_reuse.o");
int result = ebpf_program_load(file_name, BPF_PROG_TYPE_XDP, EBPF_EXECUTION_ANY, &object, &program_fd, nullptr);
int result =
ebpf_program_load(file_name, BPF_PROG_TYPE_XDP, EBPF_EXECUTION_ANY, &unique_object, &program_fd, nullptr);
REQUIRE(result == -EINVAL);
@ -2339,7 +2364,7 @@ TEST_CASE("load_native_program_negative3", "[end-to-end]")
size_t count_of_programs = 0;
int error;
const char* error_message = nullptr;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
std::wstring file_path(L"droppacket_um.dll");
const wchar_t* service_name = nullptr;
@ -2351,7 +2376,7 @@ TEST_CASE("load_native_program_negative3", "[end-to-end]")
// Load a valid native module.
error = ebpf_program_load(
"droppacket_um.dll", BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_NATIVE, &object, &program_fd, &error_message);
"droppacket_um.dll", BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_NATIVE, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
ebpf_free((void*)error_message);
@ -2376,7 +2401,7 @@ TEST_CASE("load_native_program_negative3", "[end-to-end]")
&provider_module_id, nullptr, MAP_COUNT, map_handles, PROGRAM_COUNT, program_handles) ==
ERROR_OBJECT_ALREADY_EXISTS);
bpf_object__close(object);
bpf_object__close(unique_object.release());
// Now that we have closed the object, try to load programs from the same module again. This should
// fail as the module should now be marked as "unloading".
@ -2440,15 +2465,15 @@ TEST_CASE("load_native_program_negative5", "[end_to_end]")
int result;
const char* error_message = nullptr;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
set_native_module_failures(true);
result =
ebpf_program_load("map.sys", BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_ANY, &object, &program_fd, &error_message);
result = ebpf_program_load(
"map.sys", BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_ANY, &unique_object, &program_fd, &error_message);
REQUIRE(result == -ENOENT);
}
@ -2549,12 +2574,12 @@ _load_invalid_program(_In_z_ const char* file_name, ebpf_execution_type_t execut
_test_helper_end_to_end test_helper;
int result;
bpf_object* object = nullptr;
bpf_object_ptr unique_object;
fd_t program_fd;
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &object, &program_fd, nullptr);
result = ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, execution_type, &unique_object, &program_fd, nullptr);
REQUIRE(result == expected_result);
}
@ -2769,7 +2794,7 @@ extension_reload_test(ebpf_execution_type_t execution_type)
xdp_md_t ctx0{packet0.data(), packet0.data() + packet0.size(), 0, TEST_IFINDEX};
// Try loading without the extension loaded.
bpf_object* droppacket_object;
bpf_object_ptr unique_droppacket_object;
int program_fd = -1;
const char* error_message = nullptr;
@ -2779,7 +2804,7 @@ extension_reload_test(ebpf_execution_type_t execution_type)
execution_type == EBPF_EXECUTION_NATIVE ? "droppacket_um.dll" : "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
execution_type,
&droppacket_object,
&unique_droppacket_object,
&program_fd,
&error_message) != 0);
@ -2795,7 +2820,7 @@ extension_reload_test(ebpf_execution_type_t execution_type)
execution_type == EBPF_EXECUTION_NATIVE ? "droppacket_um.dll" : "droppacket.o",
BPF_PROG_TYPE_UNSPEC,
execution_type,
&droppacket_object,
&unique_droppacket_object,
&program_fd,
&error_message) == 0);
@ -2883,15 +2908,15 @@ TEST_CASE("close_unload_test", "[close_cleanup]")
const char* error_message = nullptr;
int result;
bpf_object* object = nullptr;
bpf_link* link = nullptr;
bpf_object_ptr unique_object;
bpf_link_ptr link;
fd_t program_fd;
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
const char* file_name = "bindmonitor_tailcall_um.dll";
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_NATIVE, &object, &program_fd, &error_message);
result = ebpf_program_load(
file_name, BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_NATIVE, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -2900,17 +2925,17 @@ TEST_CASE("close_unload_test", "[close_cleanup]")
REQUIRE(result == 0);
// Set up tail calls.
struct bpf_program* callee0 = bpf_object__find_program_by_name(object, "BindMonitor_Callee0");
struct bpf_program* callee0 = bpf_object__find_program_by_name(unique_object.get(), "BindMonitor_Callee0");
REQUIRE(callee0 != nullptr);
fd_t callee0_fd = bpf_program__fd(callee0);
REQUIRE(callee0_fd > 0);
struct bpf_program* callee1 = bpf_object__find_program_by_name(object, "BindMonitor_Callee1");
struct bpf_program* callee1 = bpf_object__find_program_by_name(unique_object.get(), "BindMonitor_Callee1");
REQUIRE(callee1 != nullptr);
fd_t callee1_fd = bpf_program__fd(callee1);
REQUIRE(callee1_fd > 0);
fd_t prog_map_fd = bpf_object__find_map_fd_by_name(object, "prog_array_map");
fd_t prog_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "prog_array_map");
REQUIRE(prog_map_fd > 0);
uint32_t index = 0;
@ -2923,8 +2948,7 @@ TEST_CASE("close_unload_test", "[close_cleanup]")
REQUIRE(hook.attach_link(program_fd, &ifindex, sizeof(ifindex), &link) == EBPF_SUCCESS);
// These are needed to prevent the memory leak detector from flagging a memory leak.
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
// The block of commented code after this comment is for documentation purposes only.
//
@ -2952,7 +2976,7 @@ TEST_CASE("close_unload_test", "[close_cleanup]")
// REQUIRE(bpf_map_update_elem(prog_map_fd, &index, &ebpf_fd_invalid, 0) == 0);
*/
bpf_object__close(object);
bpf_object__close(unique_object.release());
}
// This test tests the case where a program is inserted multiple times with different keys into the same map.
@ -2962,15 +2986,15 @@ TEST_CASE("multiple_map_insert", "[close_cleanup]")
const char* error_message = nullptr;
int result;
bpf_object* object = nullptr;
bpf_link* link = nullptr;
bpf_object_ptr unique_object;
bpf_link_ptr link;
fd_t program_fd;
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
const char* file_name = "bindmonitor_tailcall_um.dll";
result =
ebpf_program_load(file_name, BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_NATIVE, &object, &program_fd, &error_message);
result = ebpf_program_load(
file_name, BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_NATIVE, &unique_object, &program_fd, &error_message);
if (error_message) {
printf("ebpf_program_load failed with %s\n", error_message);
@ -2979,17 +3003,17 @@ TEST_CASE("multiple_map_insert", "[close_cleanup]")
REQUIRE(result == 0);
// Set up tail calls.
struct bpf_program* callee0 = bpf_object__find_program_by_name(object, "BindMonitor_Callee0");
struct bpf_program* callee0 = bpf_object__find_program_by_name(unique_object.get(), "BindMonitor_Callee0");
REQUIRE(callee0 != nullptr);
fd_t callee0_fd = bpf_program__fd(callee0);
REQUIRE(callee0_fd > 0);
struct bpf_program* callee1 = bpf_object__find_program_by_name(object, "BindMonitor_Callee1");
struct bpf_program* callee1 = bpf_object__find_program_by_name(unique_object.get(), "BindMonitor_Callee1");
REQUIRE(callee1 != nullptr);
fd_t callee1_fd = bpf_program__fd(callee1);
REQUIRE(callee1_fd > 0);
fd_t prog_map_fd = bpf_object__find_map_fd_by_name(object, "prog_array_map");
fd_t prog_map_fd = bpf_object__find_map_fd_by_name(unique_object.get(), "prog_array_map");
REQUIRE(prog_map_fd > 0);
uint32_t index = 0;
@ -3013,8 +3037,7 @@ TEST_CASE("multiple_map_insert", "[close_cleanup]")
REQUIRE(hook.attach_link(program_fd, &ifindex, sizeof(ifindex), &link) == EBPF_SUCCESS);
// These are needed to prevent the memory leak detector from flagging a memory leak.
hook.detach_link(link);
hook.close_link(link);
hook.detach_and_close_link(&link);
/*
--- DO NOT REMOVE OR UN-COMMENT ---
@ -3027,5 +3050,5 @@ TEST_CASE("multiple_map_insert", "[close_cleanup]")
// REQUIRE(bpf_map_update_elem(prog_map_fd, &index, &ebpf_fd_invalid, 0) == 0);
*/
bpf_object__close(object);
bpf_object__close(unique_object.release());
}

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

@ -32,6 +32,22 @@ typedef struct _ebpf_free_memory
typedef std::unique_ptr<uint8_t, ebpf_free_memory_t> ebpf_memory_t;
typedef struct _close_bpf_link
{
void
operator()(_In_opt_ _Post_invalid_ bpf_link* link)
{
if (link != nullptr) {
if (ebpf_link_detach(link) != EBPF_SUCCESS) {
throw std::runtime_error("ebpf_link_detach failed");
}
ebpf_link_close(link);
}
}
} close_bpf_link_t;
typedef std::unique_ptr<bpf_link, close_bpf_link_t> bpf_link_ptr;
extern bool _ebpf_platform_is_preemptible;
#ifdef __cplusplus
@ -70,6 +86,24 @@ typedef class _hook_helper
public:
_hook_helper(ebpf_attach_type_t attach_type) : _attach_type(attach_type) {}
_Must_inspect_result_ ebpf_result_t
attach_link(
fd_t program_fd,
_In_reads_bytes_opt_(attach_parameters_size) void* attach_parameters,
size_t attach_parameters_size,
_Out_ bpf_link_ptr* unique_link)
{
bpf_link* link = nullptr;
ebpf_result_t result;
result = ebpf_program_attach_by_fd(program_fd, &_attach_type, attach_parameters, attach_parameters_size, &link);
if (result == EBPF_SUCCESS) {
unique_link->reset(link);
}
return result;
}
_Must_inspect_result_ ebpf_result_t
attach_link(
fd_t program_fd,
@ -172,6 +206,14 @@ typedef class _single_instance_hook : public _hook_helper
#pragma warning(pop)
}
void
detach_and_close_link(_Inout_ bpf_link_ptr* unique_link)
{
bpf_link* link = unique_link->release();
detach_link(link);
close_link(link);
}
_Must_inspect_result_ ebpf_result_t
fire(_Inout_ void* context, _Out_ uint32_t* result)
{