Create bpf_map structures from bpf_object__open() on a native file (#1160)
* Create bpf_map structures from bpf_object__open() on a native file Fixes #1140 Signed-off-by: Dave Thaler <dthaler@microsoft.com> * Fix map update when loading native object Signed-off-by: Dave Thaler <dthaler@microsoft.com> * Update tests Signed-off-by: Dave Thaler <dthaler@microsoft.com> * Fix for test Signed-off-by: Dave Thaler <dthaler@microsoft.com> * More test fixes Signed-off-by: Dave Thaler <dthaler@microsoft.com> * More test fixes Signed-off-by: Dave Thaler <dthaler@microsoft.com> * PR feedback Signed-off-by: Dave Thaler <dthaler@microsoft.com> * PR feedback Signed-off-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Родитель
e54d049866
Коммит
f863a02469
|
@ -102,7 +102,6 @@ extern "C"
|
|||
_Field_z_ const char* section_name;
|
||||
_Field_z_ const char* program_type_name;
|
||||
_Field_z_ const char* program_name;
|
||||
size_t map_count;
|
||||
size_t raw_data_size;
|
||||
_Field_size_(raw_data_size) char* raw_data;
|
||||
ebpf_stat_t* stats;
|
||||
|
|
|
@ -404,7 +404,6 @@ ebpf_api_elf_enumerate_sections(
|
|||
|
||||
info->section_name = _strdup(raw_program.section.c_str());
|
||||
info->program_type_name = _strdup(raw_program.info.type.name.c_str());
|
||||
info->map_count = raw_program.info.map_descriptors.size();
|
||||
|
||||
std::vector<uint8_t> raw_data = convert_ebpf_program_to_bytes(raw_program.prog);
|
||||
info->raw_data_size = raw_data.size();
|
||||
|
|
|
@ -66,6 +66,13 @@ _ebpf_program_load_native(
|
|||
_Inout_ struct bpf_object* object,
|
||||
_Out_ fd_t* program_fd);
|
||||
|
||||
static const char*
|
||||
_ebpf_get_section_string(
|
||||
_In_ const struct _ebpf_pe_context* pe_context,
|
||||
uintptr_t address,
|
||||
_In_ const image_section_header& section_header,
|
||||
_In_ const bounded_buffer* buffer);
|
||||
|
||||
static fd_t
|
||||
_create_file_descriptor_for_handle(ebpf_handle_t handle) noexcept
|
||||
{
|
||||
|
@ -1422,16 +1429,15 @@ _initialize_ebpf_maps_native(
|
|||
goto Exit;
|
||||
}
|
||||
|
||||
map = (ebpf_map_t*)calloc(1, sizeof(ebpf_map_t));
|
||||
if (map == nullptr) {
|
||||
result = EBPF_NO_MEMORY;
|
||||
goto Exit;
|
||||
}
|
||||
map = maps[i];
|
||||
|
||||
// Note that the map name need not match, if the map was reused
|
||||
// based on a pin path. Other fields ought to match however.
|
||||
ebpf_assert(map->map_definition.type == info.type);
|
||||
ebpf_assert(map->map_definition.key_size == info.key_size);
|
||||
ebpf_assert(map->map_definition.value_size == info.value_size);
|
||||
ebpf_assert(map->map_definition.max_entries == info.max_entries);
|
||||
|
||||
map->map_definition.type = info.type;
|
||||
map->map_definition.key_size = info.key_size;
|
||||
map->map_definition.value_size = info.value_size;
|
||||
map->map_definition.max_entries = info.max_entries;
|
||||
map->map_definition.inner_map_id = info.inner_map_id;
|
||||
map->map_fd = _create_file_descriptor_for_handle(map_handles[i]);
|
||||
if (map->map_fd == ebpf_fd_invalid) {
|
||||
|
@ -1440,14 +1446,6 @@ _initialize_ebpf_maps_native(
|
|||
}
|
||||
map->map_handle = map_handles[i];
|
||||
map_handles[i] = ebpf_handle_invalid;
|
||||
map->name = _strdup(info.name);
|
||||
if (map->name == nullptr) {
|
||||
result = EBPF_NO_MEMORY;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
maps.emplace_back(map);
|
||||
map = nullptr;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
@ -1531,7 +1529,6 @@ _initialize_ebpf_object_native(
|
|||
ebpf_assert(object.file_name != nullptr);
|
||||
ebpf_assert(object.object_name != nullptr);
|
||||
|
||||
// TODO(issue #1140): populate maps at open time
|
||||
for (auto& map : object.maps) {
|
||||
map->object = &object;
|
||||
}
|
||||
|
@ -1547,6 +1544,8 @@ Exit:
|
|||
static ebpf_result_t
|
||||
_ebpf_enumerate_native_sections(
|
||||
_In_z_ const char* file,
|
||||
_Inout_opt_ ebpf_object_t* object,
|
||||
_In_opt_z_ const char* pin_root_path,
|
||||
_Outptr_result_maybenull_ ebpf_section_info_t** infos,
|
||||
_Outptr_result_maybenull_z_ const char** error_message);
|
||||
|
||||
|
@ -1554,7 +1553,7 @@ static ebpf_result_t
|
|||
_initialize_ebpf_object_from_native_file(
|
||||
_In_z_ const char* file_name,
|
||||
_In_opt_z_ const char* pin_root_path,
|
||||
_Out_ ebpf_object_t& object,
|
||||
_Inout_ ebpf_object_t& object,
|
||||
_Outptr_result_maybenull_z_ const char** error_message) noexcept
|
||||
{
|
||||
ebpf_program_t* program = nullptr;
|
||||
|
@ -1564,7 +1563,7 @@ _initialize_ebpf_object_from_native_file(
|
|||
ebpf_assert(error_message);
|
||||
|
||||
ebpf_section_info_t* infos = nullptr;
|
||||
ebpf_result_t result = _ebpf_enumerate_native_sections(file_name, &infos, error_message);
|
||||
ebpf_result_t result = _ebpf_enumerate_native_sections(file_name, &object, pin_root_path, &infos, error_message);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
goto Exit;
|
||||
}
|
||||
|
@ -1609,9 +1608,6 @@ _initialize_ebpf_object_from_native_file(
|
|||
program = nullptr;
|
||||
}
|
||||
|
||||
// TODO(issue #1140): populate object.maps
|
||||
UNREFERENCED_PARAMETER(pin_root_path);
|
||||
|
||||
Exit:
|
||||
free(program);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
|
@ -1626,7 +1622,7 @@ static ebpf_result_t
|
|||
_initialize_ebpf_object_from_elf(
|
||||
_In_z_ const char* file_name,
|
||||
_In_opt_z_ const char* pin_root_path,
|
||||
_Out_ ebpf_object_t& object,
|
||||
_Inout_ ebpf_object_t& object,
|
||||
_Outptr_result_maybenull_z_ const char** error_message) noexcept
|
||||
{
|
||||
EBPF_LOG_ENTRY();
|
||||
|
@ -1784,12 +1780,14 @@ ebpf_free_sections(_In_opt_ ebpf_section_info_t* infos)
|
|||
|
||||
typedef struct _ebpf_pe_context
|
||||
{
|
||||
ebpf_result_t result;
|
||||
ebpf_object_t* object;
|
||||
const char* pin_root_path;
|
||||
uintptr_t image_base;
|
||||
ebpf_section_info_t* infos;
|
||||
std::map<std::string, std::string> section_names;
|
||||
std::map<std::string, std::string> program_names;
|
||||
std::map<std::string, GUID> section_program_types;
|
||||
int map_count;
|
||||
uintptr_t rdata_base;
|
||||
size_t rdata_size;
|
||||
const bounded_buffer* rdata_buffer;
|
||||
|
@ -1799,7 +1797,7 @@ typedef struct _ebpf_pe_context
|
|||
} ebpf_pe_context_t;
|
||||
|
||||
static int
|
||||
_ebpf_pe_get_map_count(
|
||||
_ebpf_pe_get_map_definitions(
|
||||
void* context,
|
||||
const VA& va,
|
||||
const std::string& section_name,
|
||||
|
@ -1810,18 +1808,73 @@ _ebpf_pe_get_map_count(
|
|||
UNREFERENCED_PARAMETER(va);
|
||||
UNREFERENCED_PARAMETER(buffer);
|
||||
|
||||
ebpf_map_t* map = nullptr;
|
||||
ebpf_pe_context_t* pe_context = (ebpf_pe_context_t*)context;
|
||||
if (section_name == "maps") {
|
||||
// bpf2c generates a section that has map names as strings at the
|
||||
// start of the section. Skip over them looking for the map_entry_t
|
||||
// which starts with a 16-byte-aligned NULL pointer.
|
||||
// which starts with an 8-byte-aligned NULL pointer where the previous
|
||||
// byte (if any) is also 00, and the following 8 bytes are non-NULL.
|
||||
uint32_t map_offset = 0;
|
||||
uint64_t zero = 0;
|
||||
while (map_offset < section_header.Misc.VirtualSize &&
|
||||
memcmp(buffer->buf + map_offset, &zero, sizeof(zero)) != 0) {
|
||||
map_offset += 16;
|
||||
while (map_offset + 16 < section_header.Misc.VirtualSize &&
|
||||
(memcmp(buffer->buf + map_offset, &zero, sizeof(zero)) != 0 ||
|
||||
(map_offset > 0 && buffer->buf[map_offset - 1] != 0) ||
|
||||
memcmp(buffer->buf + map_offset + 8, &zero, sizeof(zero)) == 0)) {
|
||||
map_offset += 8;
|
||||
}
|
||||
if (pe_context->object != nullptr) {
|
||||
for (int map_index = 0; map_offset + sizeof(map_entry_t) <= section_header.Misc.VirtualSize;
|
||||
map_offset += sizeof(map_entry_t), map_index++) {
|
||||
map_entry_t* entry = (map_entry_t*)(buffer->buf + map_offset);
|
||||
|
||||
map = (ebpf_map_t*)calloc(1, sizeof(ebpf_map_t));
|
||||
if (map == nullptr) {
|
||||
goto Error;
|
||||
}
|
||||
|
||||
map->map_handle = ebpf_handle_invalid;
|
||||
map->original_fd = (fd_t)map_index;
|
||||
map->map_definition.type = entry->definition.type;
|
||||
map->map_definition.key_size = entry->definition.key_size;
|
||||
map->map_definition.value_size = entry->definition.value_size;
|
||||
map->map_definition.max_entries = entry->definition.max_entries;
|
||||
map->map_definition.pinning = entry->definition.pinning;
|
||||
map->map_definition.inner_map_id = entry->definition.inner_id;
|
||||
map->inner_map_original_fd = entry->definition.inner_map_idx;
|
||||
map->pinned = false;
|
||||
map->reused = false;
|
||||
map->pin_path = nullptr;
|
||||
|
||||
const char* map_name =
|
||||
_ebpf_get_section_string(pe_context, (uintptr_t)entry->name, section_header, buffer);
|
||||
map->name = _strdup(map_name);
|
||||
if (map->name == nullptr) {
|
||||
pe_context->result = EBPF_NO_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
if (map->map_definition.pinning == PIN_GLOBAL_NS) {
|
||||
char pin_path_buffer[EBPF_MAX_PIN_PATH_LENGTH];
|
||||
int len = snprintf(
|
||||
pin_path_buffer,
|
||||
EBPF_MAX_PIN_PATH_LENGTH,
|
||||
"%s/%s",
|
||||
pe_context->pin_root_path ? pe_context->pin_root_path : DEFAULT_PIN_ROOT_PATH,
|
||||
map->name);
|
||||
if (len < 0 || len >= EBPF_MAX_PIN_PATH_LENGTH) {
|
||||
pe_context->result = EBPF_INVALID_ARGUMENT;
|
||||
goto Error;
|
||||
}
|
||||
map->pin_path = _strdup(pin_path_buffer);
|
||||
if (map->pin_path == nullptr) {
|
||||
pe_context->result = EBPF_NO_MEMORY;
|
||||
goto Error;
|
||||
}
|
||||
}
|
||||
pe_context->object->maps.emplace_back(map);
|
||||
map = nullptr;
|
||||
}
|
||||
}
|
||||
pe_context->map_count = (section_header.Misc.VirtualSize - map_offset) / sizeof(map_entry_t);
|
||||
} else if (section_name == ".rdata") {
|
||||
pe_context->rdata_base = pe_context->image_base + section_header.VirtualAddress;
|
||||
pe_context->rdata_size = section_header.Misc.VirtualSize;
|
||||
|
@ -1832,11 +1885,18 @@ _ebpf_pe_get_map_count(
|
|||
pe_context->data_buffer = buffer;
|
||||
}
|
||||
|
||||
EBPF_LOG_EXIT();
|
||||
EBPF_LOG_FUNCTION_SUCCESS();
|
||||
return 0;
|
||||
|
||||
Error:
|
||||
if (map) {
|
||||
clean_up_ebpf_map(map);
|
||||
}
|
||||
EBPF_LOG_FUNCTION_ERROR(pe_context->result);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char*
|
||||
static const char*
|
||||
_ebpf_get_section_string(
|
||||
_In_ const ebpf_pe_context_t* pe_context,
|
||||
uintptr_t address,
|
||||
|
@ -1876,7 +1936,7 @@ _ebpf_pe_get_section_names(
|
|||
// byte (if any) is also 00.
|
||||
uint32_t program_offset = 0;
|
||||
uint64_t zero = 0;
|
||||
while (program_offset < section_header.Misc.VirtualSize &&
|
||||
while (program_offset + sizeof(zero) <= section_header.Misc.VirtualSize &&
|
||||
(memcmp(buffer->buf + program_offset, &zero, sizeof(zero)) != 0 ||
|
||||
(program_offset > 0 && buffer->buf[program_offset - 1] != 0))) {
|
||||
program_offset += 16;
|
||||
|
@ -1946,7 +2006,6 @@ _ebpf_pe_add_section(
|
|||
_strdup(get_program_type_windows(pe_context->section_program_types[pe_section_name]).name.c_str());
|
||||
info->raw_data_size = section_header.Misc.VirtualSize;
|
||||
info->raw_data = (char*)malloc(section_header.Misc.VirtualSize);
|
||||
info->map_count = pe_context->map_count;
|
||||
if (info->raw_data == nullptr || info->program_type_name == nullptr || info->section_name == nullptr) {
|
||||
_ebpf_free_section_info(info);
|
||||
EBPF_LOG_EXIT();
|
||||
|
@ -1968,6 +2027,8 @@ _ebpf_pe_add_section(
|
|||
static ebpf_result_t
|
||||
_ebpf_enumerate_native_sections(
|
||||
_In_z_ const char* file,
|
||||
_Inout_opt_ ebpf_object_t* object,
|
||||
_In_opt_z_ const char* pin_root_path,
|
||||
_Outptr_result_maybenull_ ebpf_section_info_t** infos,
|
||||
_Outptr_result_maybenull_z_ const char** error_message)
|
||||
{
|
||||
|
@ -1980,15 +2041,19 @@ _ebpf_enumerate_native_sections(
|
|||
EBPF_RETURN_RESULT(EBPF_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
ebpf_pe_context_t context = {.image_base = pe->peHeader.nt.OptionalHeader64.ImageBase};
|
||||
IterSec(pe, _ebpf_pe_get_map_count, &context);
|
||||
ebpf_pe_context_t context = {
|
||||
.result = EBPF_SUCCESS,
|
||||
.object = object,
|
||||
.pin_root_path = pin_root_path,
|
||||
.image_base = pe->peHeader.nt.OptionalHeader64.ImageBase};
|
||||
IterSec(pe, _ebpf_pe_get_map_definitions, &context);
|
||||
IterSec(pe, _ebpf_pe_get_section_names, &context);
|
||||
IterSec(pe, _ebpf_pe_add_section, &context);
|
||||
|
||||
DestructParsedPE(pe);
|
||||
|
||||
*infos = context.infos;
|
||||
EBPF_RETURN_RESULT(EBPF_SUCCESS);
|
||||
EBPF_RETURN_RESULT(context.result);
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
|
@ -2003,7 +2068,7 @@ ebpf_enumerate_sections(
|
|||
std::string file_extension = file_name_string.substr(file_name_string.find_last_of(".") + 1);
|
||||
if (file_extension == "dll" || file_extension == "sys") {
|
||||
// Verbose is currently unused.
|
||||
EBPF_RETURN_RESULT(_ebpf_enumerate_native_sections(file, infos, error_message));
|
||||
EBPF_RETURN_RESULT(_ebpf_enumerate_native_sections(file, nullptr, nullptr, infos, error_message));
|
||||
} else {
|
||||
EBPF_RETURN_RESULT(
|
||||
ebpf_api_elf_enumerate_sections(file, nullptr, verbose, infos, error_message) ? EBPF_FAILED : EBPF_SUCCESS);
|
||||
|
@ -2925,7 +2990,7 @@ ebpf_map_next(_In_opt_ const struct bpf_map* previous, _In_ const struct bpf_obj
|
|||
goto Exit;
|
||||
}
|
||||
if (previous == nullptr) {
|
||||
map = object->maps[0];
|
||||
map = (object->maps.size() > 0) ? object->maps[0] : nullptr;
|
||||
} else {
|
||||
size_t maps_count = object->maps.size();
|
||||
for (size_t i = 0; i < maps_count; i++) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <iomanip>
|
||||
#include <locale>
|
||||
#include <netsh.h>
|
||||
#include "bpf/libbpf.h"
|
||||
#include "elf.h"
|
||||
#include "tokens.h"
|
||||
#include "utilities.h"
|
||||
|
@ -69,6 +70,13 @@ handle_ebpf_show_disassembly(
|
|||
}
|
||||
}
|
||||
|
||||
static PCSTR
|
||||
_get_map_type_name(ebpf_map_type_t type)
|
||||
{
|
||||
int index = (type >= _countof(_ebpf_map_display_names)) ? 0 : type;
|
||||
return _ebpf_map_display_names[index];
|
||||
}
|
||||
|
||||
DWORD
|
||||
handle_ebpf_show_sections(
|
||||
LPCWSTR machine, LPWSTR* argv, DWORD current_index, DWORD argc, DWORD flags, LPCVOID data, BOOL* done)
|
||||
|
@ -126,7 +134,6 @@ handle_ebpf_show_sections(
|
|||
}
|
||||
|
||||
ebpf_section_info_t* section_data = nullptr;
|
||||
|
||||
const char* error_message = nullptr;
|
||||
if (ebpf_enumerate_sections(filename.c_str(), level == VL_VERBOSE, §ion_data, &error_message) != 0) {
|
||||
std::cerr << error_message << std::endl;
|
||||
|
@ -137,8 +144,9 @@ handle_ebpf_show_sections(
|
|||
|
||||
if (level == VL_NORMAL) {
|
||||
std::cout << "\n";
|
||||
std::cout << " Section Type # Maps Size\n";
|
||||
std::cout << "==================== ========= ====== ======\n";
|
||||
std::cout << " Size\n";
|
||||
std::cout << " Section Type (bytes)\n";
|
||||
std::cout << "==================== ========= =======\n";
|
||||
}
|
||||
for (auto current_section = section_data; current_section != nullptr; current_section = current_section->next) {
|
||||
if (!section.empty() && strcmp(current_section->section_name, section.c_str()) != 0) {
|
||||
|
@ -146,22 +154,43 @@ handle_ebpf_show_sections(
|
|||
}
|
||||
if (level == VL_NORMAL) {
|
||||
std::cout << std::setw(20) << std::right << current_section->section_name << " " << std::setw(9)
|
||||
<< current_section->program_type_name << " " << std::setw(6) << current_section->map_count
|
||||
<< " " << std::setw(6) << current_section->raw_data_size << "\n";
|
||||
<< current_section->program_type_name << " " << std::setw(7) << current_section->raw_data_size
|
||||
<< "\n";
|
||||
} else {
|
||||
std::cout << "\n";
|
||||
std::cout << "Section : " << current_section->section_name << "\n";
|
||||
std::cout << "Program Type : " << current_section->program_type_name << "\n";
|
||||
std::cout << "# Maps : " << current_section->map_count << "\n";
|
||||
std::cout << "Size : " << current_section->raw_data_size << " bytes\n";
|
||||
for (auto stat = current_section->stats; stat != nullptr; stat = stat->next) {
|
||||
std::cout << std::setw(13) << std::left << stat->key << ": " << stat->value << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ebpf_free_sections(section_data);
|
||||
ebpf_free_string(error_message);
|
||||
|
||||
// Show maps.
|
||||
std::cout << "\n";
|
||||
std::cout << " Key Value Max\n";
|
||||
std::cout << " Map Type Size Size Entries Name\n";
|
||||
std::cout << "================== ==== ===== ======= ========\n";
|
||||
bpf_object* object = bpf_object__open(filename.c_str());
|
||||
if (object == nullptr) {
|
||||
std::cout << "Couldn't get maps from " << filename << "\n";
|
||||
return ERROR_SUPPRESS_OUTPUT;
|
||||
}
|
||||
bpf_map* map;
|
||||
bpf_object__for_each_map(map, object)
|
||||
{
|
||||
printf(
|
||||
"%18s%6u%7u%9u %s\n",
|
||||
_get_map_type_name(bpf_map__type(map)),
|
||||
bpf_map__key_size(map),
|
||||
bpf_map__value_size(map),
|
||||
bpf_map__max_entries(map),
|
||||
bpf_map__name(map));
|
||||
}
|
||||
bpf_object__close(object);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ _is_native_program(_In_z_ const char* file_name)
|
|||
{
|
||||
std::string file_name_string(file_name);
|
||||
std::string file_extension = file_name_string.substr(file_name_string.find_last_of(".") + 1);
|
||||
if (file_extension == "dll") {
|
||||
if (file_extension == "dll" || file_extension == "sys") {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1713,6 +1713,12 @@ _map_reuse_test(ebpf_execution_type_t execution_type)
|
|||
error = bpf_obj_pin(outer_map_fd, "/ebpf/global/outer_map");
|
||||
REQUIRE(error == 0);
|
||||
|
||||
// The outer map name created above should not have a name.
|
||||
bpf_map_info info;
|
||||
uint32_t info_size = sizeof(info);
|
||||
REQUIRE(bpf_obj_get_info_by_fd(outer_map_fd, &info, &info_size) == 0);
|
||||
REQUIRE(info.name[0] == 0);
|
||||
|
||||
int port_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32), sizeof(__u32), 1, 0);
|
||||
REQUIRE(port_map_fd > 0);
|
||||
|
||||
|
@ -1730,6 +1736,11 @@ _map_reuse_test(ebpf_execution_type_t execution_type)
|
|||
program_load_attach_helper_t program_helper(
|
||||
file_name, BPF_PROG_TYPE_XDP, "lookup_update", EBPF_EXECUTION_ANY, &ifindex, sizeof(ifindex), hook);
|
||||
|
||||
// The outer map we created earlier should still not have a name even though there is a name in the file,
|
||||
// since the unnamed map was reused.
|
||||
REQUIRE(bpf_obj_get_info_by_fd(outer_map_fd, &info, &info_size) == 0);
|
||||
REQUIRE(info.name[0] == 0);
|
||||
|
||||
auto packet = prepare_udp_packet(10, ETHERNET_TYPE_IPV4);
|
||||
xdp_md_t ctx{packet.data(), packet.data() + packet.size(), 0, TEST_IFINDEX};
|
||||
int hook_result;
|
||||
|
@ -1754,6 +1765,53 @@ _map_reuse_test(ebpf_execution_type_t execution_type)
|
|||
|
||||
DECLARE_JIT_TEST_CASES("map_reuse", "[end_to_end]", _map_reuse_test);
|
||||
|
||||
// Try to reuse a map of the wrong type.
|
||||
static void
|
||||
_wrong_map_reuse_test(ebpf_execution_type_t execution_type)
|
||||
{
|
||||
_test_helper_end_to_end test_helper;
|
||||
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_reuse_um.dll" : "map_reuse.o");
|
||||
|
||||
// First create and pin the maps manually.
|
||||
int inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32), sizeof(__u32), 1, 0);
|
||||
REQUIRE(inner_map_fd > 0);
|
||||
|
||||
int outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_HASH_OF_MAPS, nullptr, sizeof(__u32), inner_map_fd, 1, 0);
|
||||
REQUIRE(outer_map_fd > 0);
|
||||
|
||||
// Pin the outer map and port map to the wrong paths so they won't match what is in the ebpf program.
|
||||
REQUIRE(bpf_obj_pin(outer_map_fd, "/ebpf/global/port_map") == 0);
|
||||
|
||||
int port_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32), sizeof(__u32), 1, 0);
|
||||
REQUIRE(port_map_fd > 0);
|
||||
|
||||
// Pin port map.
|
||||
REQUIRE(bpf_obj_pin(port_map_fd, "/ebpf/global/outer_map") == 0);
|
||||
|
||||
// Open eBPF program file.
|
||||
bpf_object* object = bpf_object__open(file_name);
|
||||
REQUIRE(object != nullptr);
|
||||
bpf_program* program = bpf_object__next_program(object, nullptr);
|
||||
REQUIRE(program != nullptr);
|
||||
|
||||
// Try to load the program. This should fail because the maps can't be reused.
|
||||
REQUIRE(bpf_object__load(object) == -EINVAL);
|
||||
|
||||
bpf_object__close(object);
|
||||
|
||||
Platform::_close(outer_map_fd);
|
||||
Platform::_close(inner_map_fd);
|
||||
Platform::_close(port_map_fd);
|
||||
|
||||
REQUIRE(ebpf_object_unpin("/ebpf/global/outer_map") == EBPF_SUCCESS);
|
||||
REQUIRE(ebpf_object_unpin("/ebpf/global/port_map") == EBPF_SUCCESS);
|
||||
}
|
||||
|
||||
DECLARE_JIT_TEST_CASES("wrong_map_reuse", "[end_to_end]", _wrong_map_reuse_test);
|
||||
|
||||
static void
|
||||
_auto_pinned_maps_test(ebpf_execution_type_t execution_type)
|
||||
{
|
||||
|
@ -2213,6 +2271,25 @@ TEST_CASE("load_native_program_negative4", "[end-to-end]")
|
|||
Platform::_delete_service(service_handle);
|
||||
}
|
||||
|
||||
// Try to load a .sys in user mode.
|
||||
TEST_CASE("load_native_program_negative5", "[end_to_end]")
|
||||
{
|
||||
_test_helper_end_to_end test_helper;
|
||||
|
||||
int result;
|
||||
const char* error_message = nullptr;
|
||||
bpf_object* object = nullptr;
|
||||
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);
|
||||
REQUIRE(result == -ENOENT);
|
||||
}
|
||||
|
||||
// The below tests try to load native drivers for invalid programs (that will fail verification).
|
||||
// Since verification can be skipped in bpf2c for only Debug builds, these tests are applicable
|
||||
// only for Debug build.
|
||||
|
|
|
@ -94,9 +94,14 @@ TEST_CASE("show sections bpf.o", "[netsh][sections]")
|
|||
REQUIRE(result == NO_ERROR);
|
||||
REQUIRE(
|
||||
output == "\n"
|
||||
" Section Type # Maps Size\n"
|
||||
"==================== ========= ====== ======\n"
|
||||
" .text xdp 0 16\n");
|
||||
" Size\n"
|
||||
" Section Type (bytes)\n"
|
||||
"==================== ========= =======\n"
|
||||
" .text xdp 16\n"
|
||||
"\n"
|
||||
" Key Value Max\n"
|
||||
" Map Type Size Size Entries Name\n"
|
||||
"================== ==== ===== ======= ========\n");
|
||||
}
|
||||
|
||||
// Test specifying a section name.
|
||||
|
@ -109,7 +114,6 @@ TEST_CASE("show sections bpf.o .text", "[netsh][sections]")
|
|||
output == "\n"
|
||||
"Section : .text\n"
|
||||
"Program Type : xdp\n"
|
||||
"# Maps : 0\n"
|
||||
"Size : 16 bytes\n"
|
||||
"Instructions : 2\n"
|
||||
"adjust_head : 0\n"
|
||||
|
@ -128,7 +132,11 @@ TEST_CASE("show sections bpf.o .text", "[netsh][sections]")
|
|||
"map_in_map : 0\n"
|
||||
"other : 2\n"
|
||||
"packet_access: 0\n"
|
||||
"store : 0\n");
|
||||
"store : 0\n"
|
||||
"\n"
|
||||
" Key Value Max\n"
|
||||
" Map Type Size Size Entries Name\n"
|
||||
"================== ==== ===== ======= ========\n");
|
||||
}
|
||||
|
||||
// Test a .sys file.
|
||||
|
@ -140,9 +148,14 @@ TEST_CASE("show sections bpf.sys", "[netsh][sections]")
|
|||
|
||||
REQUIRE(
|
||||
output == "\n"
|
||||
" Section Type # Maps Size\n"
|
||||
"==================== ========= ====== ======\n"
|
||||
" .text xdp 0 1752\n");
|
||||
" Size\n"
|
||||
" Section Type (bytes)\n"
|
||||
"==================== ========= =======\n"
|
||||
" .text xdp 1752\n"
|
||||
"\n"
|
||||
" Key Value Max\n"
|
||||
" Map Type Size Size Entries Name\n"
|
||||
"================== ==== ===== ======= ========\n");
|
||||
}
|
||||
|
||||
// Test a DLL with multiple maps in the map section.
|
||||
|
@ -153,9 +166,17 @@ TEST_CASE("show sections map_reuse_um.dll", "[netsh][sections]")
|
|||
REQUIRE(result == NO_ERROR);
|
||||
REQUIRE(
|
||||
output == "\n"
|
||||
" Section Type # Maps Size\n"
|
||||
"==================== ========= ====== ======\n"
|
||||
" xdp_prog xdp 3 1087\n");
|
||||
" Size\n"
|
||||
" Section Type (bytes)\n"
|
||||
"==================== ========= =======\n"
|
||||
" xdp_prog xdp 1087\n"
|
||||
"\n"
|
||||
" Key Value Max\n"
|
||||
" Map Type Size Size Entries Name\n"
|
||||
"================== ==== ===== ======= ========\n"
|
||||
" Hash of maps 4 4 1 outer_map\n"
|
||||
" Array 4 4 1 inner_map\n"
|
||||
" Array 4 4 1 port_map\n");
|
||||
}
|
||||
|
||||
// Test a .dll file with multiple programs.
|
||||
|
@ -167,11 +188,17 @@ TEST_CASE("show sections tail_call_multiple_um.dll", "[netsh][sections]")
|
|||
REQUIRE(result == NO_ERROR);
|
||||
REQUIRE(
|
||||
output == "\n"
|
||||
" Section Type # Maps Size\n"
|
||||
"==================== ========= ====== ======\n"
|
||||
" xdp_prog xdp 0 413\n"
|
||||
" xdp_prog/0 xdp 0 413\n"
|
||||
" xdp_prog/1 xdp 0 190\n");
|
||||
" Size\n"
|
||||
" Section Type (bytes)\n"
|
||||
"==================== ========= =======\n"
|
||||
" xdp_prog xdp 413\n"
|
||||
" xdp_prog/0 xdp 413\n"
|
||||
" xdp_prog/1 xdp 190\n"
|
||||
"\n"
|
||||
" Key Value Max\n"
|
||||
" Map Type Size Size Entries Name\n"
|
||||
"================== ==== ===== ======= ========\n"
|
||||
" Program array 4 4 10 map\n");
|
||||
}
|
||||
|
||||
// Test a .sys file with multiple programs, including ones with long names.
|
||||
|
@ -183,12 +210,19 @@ TEST_CASE("show sections cgroup_sock_addr.sys", "[netsh][sections]")
|
|||
REQUIRE(result == NO_ERROR);
|
||||
REQUIRE(
|
||||
output == "\n"
|
||||
" Section Type # Maps Size\n"
|
||||
"==================== ========= ====== ======\n"
|
||||
" cgroup/connect4 sock_addr 2 594\n"
|
||||
" cgroup/connect6 sock_addr 2 728\n"
|
||||
" cgroup/recv_accept4 sock_addr 2 594\n"
|
||||
" cgroup/recv_accept6 sock_addr 2 728\n");
|
||||
" Size\n"
|
||||
" Section Type (bytes)\n"
|
||||
"==================== ========= =======\n"
|
||||
" cgroup/connect4 sock_addr 594\n"
|
||||
" cgroup/connect6 sock_addr 728\n"
|
||||
" cgroup/recv_accept4 sock_addr 594\n"
|
||||
" cgroup/recv_accept6 sock_addr 728\n"
|
||||
"\n"
|
||||
" Key Value Max\n"
|
||||
" Map Type Size Size Entries Name\n"
|
||||
"================== ==== ===== ======= ========\n"
|
||||
" Hash 44 4 1 ingress_connection_policy_map\n"
|
||||
" Hash 44 4 1 egress_connection_policy_map\n");
|
||||
}
|
||||
|
||||
TEST_CASE("show verification nosuchfile.o", "[netsh][verification]")
|
||||
|
|
|
@ -257,7 +257,10 @@ _preprocess_load_native_module(_Inout_ service_context_t* context)
|
|||
|
||||
auto get_function =
|
||||
reinterpret_cast<decltype(&get_metadata_table)>(GetProcAddress(context->dll, "get_metadata_table"));
|
||||
REQUIRE(get_function != nullptr);
|
||||
if (get_function == nullptr) {
|
||||
REQUIRE(_expect_native_module_load_failures);
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_table_t* table = get_function();
|
||||
REQUIRE(table != nullptr);
|
||||
|
@ -479,8 +482,8 @@ Glue_delete_service(SC_HANDLE handle)
|
|||
// Delete the service if it has not been loaded yet. Otherwise
|
||||
// mark it pending for delete.
|
||||
if (!context->loaded) {
|
||||
_service_path_to_context_map.erase(path);
|
||||
ebpf_free(context);
|
||||
_service_path_to_context_map.erase(path);
|
||||
} else {
|
||||
context->delete_pending = true;
|
||||
}
|
||||
|
|
|
@ -1981,6 +1981,16 @@ TEST_CASE("bpf_object__open_file with .dll", "[libbpf]")
|
|||
|
||||
REQUIRE(bpf_object__next_program(object, program) == nullptr);
|
||||
|
||||
struct bpf_map* map = bpf_object__next_map(object, nullptr);
|
||||
REQUIRE(map != nullptr);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(map == nullptr);
|
||||
|
||||
// Trying to attach the program should fail since it's not loaded yet.
|
||||
bpf_link* link = bpf_program__attach(program);
|
||||
REQUIRE(link == nullptr);
|
||||
|
@ -1989,6 +1999,17 @@ TEST_CASE("bpf_object__open_file with .dll", "[libbpf]")
|
|||
// Load the program.
|
||||
REQUIRE(bpf_object__load(object) == 0);
|
||||
|
||||
// The maps should now have FDs.
|
||||
map = bpf_object__next_map(object, nullptr);
|
||||
REQUIRE(map != nullptr);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(map == nullptr);
|
||||
|
||||
// Attach should now succeed.
|
||||
link = bpf_program__attach(program);
|
||||
REQUIRE(link != nullptr);
|
||||
|
@ -2022,6 +2043,16 @@ TEST_CASE("bpf_object__load with .o", "[libbpf]")
|
|||
|
||||
REQUIRE(bpf_program__set_type(program, BPF_PROG_TYPE_XDP) == 0);
|
||||
|
||||
struct bpf_map* map = bpf_object__next_map(object, nullptr);
|
||||
REQUIRE(map != nullptr);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(map == nullptr);
|
||||
|
||||
// Trying to attach the program should fail since it's not loaded yet.
|
||||
bpf_link* link = bpf_program__attach(program);
|
||||
REQUIRE(link == nullptr);
|
||||
|
@ -2034,6 +2065,17 @@ TEST_CASE("bpf_object__load with .o", "[libbpf]")
|
|||
link = bpf_program__attach(program);
|
||||
REQUIRE(link != nullptr);
|
||||
|
||||
// The maps should now have FDs.
|
||||
map = bpf_object__next_map(object, nullptr);
|
||||
REQUIRE(map != nullptr);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
|
||||
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
|
||||
map = bpf_object__next_map(object, map);
|
||||
REQUIRE(map == nullptr);
|
||||
|
||||
REQUIRE(bpf_link__destroy(link) == 0);
|
||||
bpf_object__close(object);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче