Prevent mismatched program types in PROG_ARRAY maps (#374)
* Prevent mismatched program types in PROG_ARRAY maps * Each prog array map has a natural progtype, determined when asociating it from a program, or when adding the first program to it, if not associated with any program. * Trying to add a program with mismatching type will fail * Added libbpf bpf_create_map() API * Fixed error returns from several libbpf APIs to be negative * For efficiency, ebpf_program_get_properties now returns a pointer rather than copying the data inside the execution context, and is renamed to ebpf_program_get_parameters() to match what its return type always was. * Fixed a bug in map size calculation that resulted in a huge amount of memory being allocated * Updated return type of bpf_tail_call to the value meant to signal stack unwind needed Signed-off-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Родитель
014ee34392
Коммит
7c12adb067
|
@ -5,6 +5,7 @@
|
|||
|
||||
LIBRARY
|
||||
EXPORTS
|
||||
bpf_create_map
|
||||
bpf_link__destroy
|
||||
bpf_link__pin
|
||||
bpf_link__unpin
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 77308c91d8fe8da862329e4ce54cfa43d027a8a4
|
||||
Subproject commit e2dfcd2a3255418fe983691382421b4fa1dac9c2
|
|
@ -21,6 +21,7 @@ enum bpf_prog_type
|
|||
{
|
||||
BPF_PROG_TYPE_UNKNOWN,
|
||||
BPF_PROG_TYPE_XDP,
|
||||
BPF_PROG_TYPE_BIND, // TODO(#333): replace with cross-platform program type
|
||||
};
|
||||
|
||||
enum bpf_attach_type
|
||||
|
|
|
@ -14,6 +14,21 @@
|
|||
// minimize diffs until libbpf becomes cross-platform capable. This is a temporary workaround for
|
||||
// issue #351 until we can compile and use libbpf.c directly.
|
||||
|
||||
int
|
||||
bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, uint32_t map_flags)
|
||||
{
|
||||
if (key_size <= 0 || value_size <= 0 || max_entries <= 0) {
|
||||
return libbpf_err(-EINVAL);
|
||||
}
|
||||
|
||||
fd_t map_fd;
|
||||
ebpf_result_t result = ebpf_create_map(map_type, key_size, value_size, max_entries, map_flags, &map_fd);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
return libbpf_err(-result);
|
||||
}
|
||||
return map_fd;
|
||||
}
|
||||
|
||||
struct bpf_map*
|
||||
bpf_map__next(const struct bpf_map* previous, const struct bpf_object* object)
|
||||
{
|
||||
|
@ -181,11 +196,11 @@ bpf_object__find_map_fd_by_name(const struct bpf_object* obj, const char* name)
|
|||
int
|
||||
bpf_map__set_pin_path(struct bpf_map* map, const char* path)
|
||||
{
|
||||
return libbpf_err(ebpf_map_set_pin_path(map, path));
|
||||
return libbpf_err(-ebpf_map_set_pin_path(map, path));
|
||||
}
|
||||
|
||||
int
|
||||
bpf_map_update_elem(int fd, const void* key, const void* value, uint64_t flags)
|
||||
{
|
||||
return libbpf_err(ebpf_map_update_element(fd, key, value, flags));
|
||||
return libbpf_err(-ebpf_map_update_element(fd, key, value, flags));
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ _get_ebpf_program_type(enum bpf_prog_type type)
|
|||
switch (type) {
|
||||
case BPF_PROG_TYPE_XDP:
|
||||
return &EBPF_PROGRAM_TYPE_XDP;
|
||||
case BPF_PROG_TYPE_BIND:
|
||||
return &EBPF_PROGRAM_TYPE_BIND;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -51,12 +53,16 @@ bpf_prog_load(const char* file_name, enum bpf_prog_type type, struct bpf_object*
|
|||
const ebpf_program_type_t* program_type = _get_ebpf_program_type(type);
|
||||
|
||||
if (program_type == nullptr) {
|
||||
return EBPF_INVALID_ARGUMENT;
|
||||
return libbpf_err(-EBPF_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
const char* log_buffer;
|
||||
return (int)ebpf_program_load(
|
||||
file_name, program_type, nullptr, EBPF_EXECUTION_ANY, object, (fd_t*)program_fd, &log_buffer);
|
||||
ebpf_result_t result =
|
||||
ebpf_program_load(file_name, program_type, nullptr, EBPF_EXECUTION_ANY, object, (fd_t*)program_fd, &log_buffer);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
return libbpf_err(-result);
|
||||
}
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -162,7 +168,7 @@ bpf_program__pin(struct bpf_program* prog, const char* path)
|
|||
|
||||
err = ebpf_object_pin(prog->fd, path);
|
||||
if (err) {
|
||||
return libbpf_err(err);
|
||||
return libbpf_err(-err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -262,7 +268,7 @@ bpf_link__destroy(struct bpf_link* link)
|
|||
// detach before closing the handle.
|
||||
ebpf_handle_t link_handle = (ebpf_handle_t)link;
|
||||
uint32_t result = ebpf_api_close_handle(link_handle);
|
||||
return (int)result;
|
||||
return libbpf_err(-(int)result);
|
||||
}
|
||||
|
||||
enum bpf_attach_type
|
||||
|
|
|
@ -110,6 +110,7 @@ static const EbpfMapType windows_map_types[] = {
|
|||
{BPF_MAP_TYPE(UNSPECIFIED)},
|
||||
{BPF_MAP_TYPE(HASH)},
|
||||
{BPF_MAP_TYPE(ARRAY), true},
|
||||
{BPF_MAP_TYPE(PROG_ARRAY), true, EbpfMapValueType::PROGRAM},
|
||||
};
|
||||
|
||||
EbpfMapType
|
||||
|
|
|
@ -48,8 +48,8 @@ static ebpf_helper_function_prototype_t _ebpf_map_helper_function_prototype[] =
|
|||
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
|
||||
{(uint32_t)(intptr_t)bpf_tail_call,
|
||||
"bpf_tail_call",
|
||||
EBPF_RETURN_TYPE_INTEGER,
|
||||
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_ANYTHING}},
|
||||
EBPF_RETURN_TYPE_INTEGER_OR_NO_RETURN_IF_SUCCEED,
|
||||
{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}},
|
||||
|
@ -607,15 +607,16 @@ _ebpf_core_protocol_query_program_info(
|
|||
ebpf_result_t retval;
|
||||
ebpf_program_t* program = NULL;
|
||||
size_t required_reply_length;
|
||||
ebpf_program_parameters_t parameters;
|
||||
const ebpf_program_parameters_t* parameters;
|
||||
|
||||
retval = ebpf_reference_object_by_handle(request->handle, EBPF_OBJECT_PROGRAM, (ebpf_object_t**)&program);
|
||||
if (retval != EBPF_SUCCESS)
|
||||
goto Done;
|
||||
|
||||
ebpf_program_get_properties(program, ¶meters);
|
||||
parameters = ebpf_program_get_parameters(program);
|
||||
|
||||
retval = ebpf_safe_size_t_add(parameters.section_name.length, parameters.file_name.length, &required_reply_length);
|
||||
retval =
|
||||
ebpf_safe_size_t_add(parameters->section_name.length, parameters->file_name.length, &required_reply_length);
|
||||
if (retval != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
@ -632,11 +633,11 @@ _ebpf_core_protocol_query_program_info(
|
|||
}
|
||||
|
||||
reply->file_name_offset = EBPF_OFFSET_OF(struct _ebpf_operation_query_program_info_reply, data);
|
||||
reply->section_name_offset = reply->file_name_offset + (uint16_t)parameters.file_name.length;
|
||||
reply->section_name_offset = reply->file_name_offset + (uint16_t)parameters->file_name.length;
|
||||
|
||||
memcpy(reply->data, parameters.file_name.value, parameters.file_name.length);
|
||||
memcpy(reply->data + parameters.file_name.length, parameters.section_name.value, parameters.section_name.length);
|
||||
reply->code_type = parameters.code_type;
|
||||
memcpy(reply->data, parameters->file_name.value, parameters->file_name.length);
|
||||
memcpy(reply->data + parameters->file_name.length, parameters->section_name.value, parameters->section_name.length);
|
||||
reply->code_type = parameters->code_type;
|
||||
|
||||
reply->header.length = (uint16_t)required_reply_length;
|
||||
|
||||
|
|
|
@ -105,7 +105,6 @@ ebpf_result_t
|
|||
ebpf_link_attach_program(ebpf_link_t* link, ebpf_program_t* program)
|
||||
{
|
||||
ebpf_result_t return_value = EBPF_SUCCESS;
|
||||
ebpf_program_parameters_t program_parameters;
|
||||
ebpf_lock_state_t state;
|
||||
state = ebpf_lock_lock(&link->attach_lock);
|
||||
if (link->program) {
|
||||
|
@ -113,8 +112,8 @@ ebpf_link_attach_program(ebpf_link_t* link, ebpf_program_t* program)
|
|||
goto Done;
|
||||
}
|
||||
|
||||
ebpf_program_get_properties(program, &program_parameters);
|
||||
if (memcmp(&program_parameters.program_type, &link->program_type, sizeof(link->program_type)) != 0) {
|
||||
const ebpf_program_type_t* program_type = ebpf_program_type(program);
|
||||
if (memcmp(program_type, &link->program_type, sizeof(link->program_type)) != 0) {
|
||||
return_value = EBPF_INVALID_ARGUMENT;
|
||||
goto Done;
|
||||
}
|
||||
|
|
|
@ -16,10 +16,18 @@ typedef struct _ebpf_core_map
|
|||
uint8_t* data;
|
||||
} ebpf_core_map_t;
|
||||
|
||||
typedef struct _ebpf_program_array_map
|
||||
{
|
||||
ebpf_core_map_t core_map;
|
||||
bool is_program_type_set;
|
||||
ebpf_program_type_t program_type;
|
||||
} ebpf_program_array_map_t;
|
||||
|
||||
typedef struct _ebpf_map_function_table
|
||||
{
|
||||
ebpf_core_map_t* (*create_map)(_In_ const ebpf_map_definition_t* map_definition);
|
||||
void (*delete_map)(_In_ ebpf_core_map_t* map);
|
||||
ebpf_result_t (*associate_program)(_In_ ebpf_map_t* map, _In_ const ebpf_program_t* program);
|
||||
uint8_t* (*find_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key);
|
||||
ebpf_object_t* (*get_object_from_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key);
|
||||
ebpf_result_t (*update_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_ const uint8_t* value);
|
||||
|
@ -36,10 +44,10 @@ ebpf_map_get_definition(_In_ const ebpf_map_t* map)
|
|||
}
|
||||
|
||||
static ebpf_core_map_t*
|
||||
_create_array_map_with_extra_value_size(_In_ const ebpf_map_definition_t* map_definition, size_t extra_value_size)
|
||||
_create_array_map_with_extra_value_size(
|
||||
size_t map_struct_size, _In_ const ebpf_map_definition_t* map_definition, size_t extra_value_size)
|
||||
{
|
||||
ebpf_result_t retval;
|
||||
size_t map_entry_size = sizeof(ebpf_core_map_t);
|
||||
size_t map_data_size = 0;
|
||||
ebpf_core_map_t* map = NULL;
|
||||
|
||||
|
@ -54,20 +62,21 @@ _create_array_map_with_extra_value_size(_In_ const ebpf_map_definition_t* map_de
|
|||
goto Done;
|
||||
}
|
||||
|
||||
retval = ebpf_safe_size_t_multiply(map_data_size, map_entry_size, &map_entry_size);
|
||||
size_t full_map_size;
|
||||
retval = ebpf_safe_size_t_add(map_struct_size, map_data_size, &full_map_size);
|
||||
if (retval != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// allocate
|
||||
map = ebpf_allocate(map_entry_size);
|
||||
map = ebpf_allocate(full_map_size);
|
||||
if (map == NULL) {
|
||||
goto Done;
|
||||
}
|
||||
memset(map, 0, map_entry_size);
|
||||
memset(map, 0, full_map_size);
|
||||
|
||||
map->ebpf_map_definition = *map_definition;
|
||||
map->data = (uint8_t*)(map + 1);
|
||||
map->data = ((uint8_t*)map) + map_struct_size;
|
||||
|
||||
Done:
|
||||
return map;
|
||||
|
@ -76,7 +85,7 @@ Done:
|
|||
static ebpf_core_map_t*
|
||||
_create_array_map(_In_ const ebpf_map_definition_t* map_definition)
|
||||
{
|
||||
return _create_array_map_with_extra_value_size(map_definition, 0);
|
||||
return _create_array_map_with_extra_value_size(sizeof(ebpf_core_map_t), map_definition, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -94,7 +103,7 @@ _find_array_map_entry_with_extra_value_size(_In_ ebpf_core_map_t* map, _In_ cons
|
|||
|
||||
key_value = *(uint32_t*)key;
|
||||
|
||||
if (key_value > map->ebpf_map_definition.max_entries)
|
||||
if (key_value >= map->ebpf_map_definition.max_entries)
|
||||
return NULL;
|
||||
|
||||
// The following addition is safe since it was checked during map creation.
|
||||
|
@ -178,7 +187,8 @@ _next_array_map_key(_In_ ebpf_core_map_t* map, _In_ const uint8_t* previous_key,
|
|||
static ebpf_core_map_t*
|
||||
_create_prog_array_map(_In_ const ebpf_map_definition_t* map_definition)
|
||||
{
|
||||
return _create_array_map_with_extra_value_size(map_definition, sizeof(struct _ebpf_program*));
|
||||
return _create_array_map_with_extra_value_size(
|
||||
sizeof(ebpf_program_array_map_t), map_definition, sizeof(struct _ebpf_program*));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -197,6 +207,31 @@ _delete_array_map_with_references(_In_ ebpf_core_map_t* map)
|
|||
ebpf_free(map);
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
_associate_program_with_prog_array_map(_In_ ebpf_core_map_t* map, _In_ const ebpf_program_t* program)
|
||||
{
|
||||
ebpf_assert(map->ebpf_map_definition.type == BPF_MAP_TYPE_PROG_ARRAY);
|
||||
ebpf_program_array_map_t* program_array = (ebpf_program_array_map_t*)map;
|
||||
|
||||
// Validate that the program type is
|
||||
// not in conflict with the map's program type.
|
||||
const ebpf_program_type_t* program_type = ebpf_program_type(program);
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
|
||||
ebpf_lock_state_t lock_state = ebpf_lock_lock(&map->lock);
|
||||
|
||||
if (!program_array->is_program_type_set) {
|
||||
program_array->is_program_type_set = TRUE;
|
||||
program_array->program_type = *program_type;
|
||||
} else if (memcmp(&program_array->program_type, program_type, sizeof(*program_type)) != 0) {
|
||||
result = EBPF_INVALID_FD;
|
||||
}
|
||||
|
||||
ebpf_lock_unlock(&map->lock, lock_state);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
_update_prog_array_map_entry_with_handle(
|
||||
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_ const uint8_t* value, uintptr_t value_handle)
|
||||
|
@ -218,8 +253,22 @@ _update_prog_array_map_entry_with_handle(
|
|||
// The following addition is safe since it was checked during map creation.
|
||||
size_t actual_value_size = ((size_t)map->ebpf_map_definition.value_size) + sizeof(struct _ebpf_program*);
|
||||
|
||||
// TODO(issue #344): validate that the program type is
|
||||
// Validate that the program type is
|
||||
// not in conflict with the map's program type.
|
||||
const ebpf_program_type_t* program_type = ebpf_program_type(program);
|
||||
ebpf_program_array_map_t* program_array = (ebpf_program_array_map_t*)map;
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
|
||||
ebpf_lock_state_t lock_state = ebpf_lock_lock(&map->lock);
|
||||
|
||||
if (!program_array->is_program_type_set) {
|
||||
program_array->is_program_type_set = TRUE;
|
||||
program_array->program_type = *program_type;
|
||||
} else if (memcmp(&program_array->program_type, program_type, sizeof(*program_type)) != 0) {
|
||||
ebpf_object_release_reference((ebpf_object_t*)program);
|
||||
result = EBPF_INVALID_FD;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// Store the literal value.
|
||||
uint8_t* entry = &map->data[*key * actual_value_size];
|
||||
|
@ -228,7 +277,10 @@ _update_prog_array_map_entry_with_handle(
|
|||
// Store program pointer after the value.
|
||||
memcpy(entry + map->ebpf_map_definition.value_size, &program, sizeof(void*));
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
Done:
|
||||
ebpf_lock_unlock(&map->lock, lock_state);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
|
@ -393,6 +445,7 @@ ebpf_map_function_table_t ebpf_map_function_tables[] = {
|
|||
{// BPF_MAP_TYPE_HASH
|
||||
_create_hash_map,
|
||||
_delete_hash_map,
|
||||
NULL,
|
||||
_find_hash_map_entry,
|
||||
NULL,
|
||||
_update_hash_map_entry,
|
||||
|
@ -402,6 +455,7 @@ ebpf_map_function_table_t ebpf_map_function_tables[] = {
|
|||
{// BPF_MAP_TYPE_ARRAY
|
||||
_create_array_map,
|
||||
_delete_array_map,
|
||||
NULL,
|
||||
_find_array_map_entry,
|
||||
NULL,
|
||||
_update_array_map_entry,
|
||||
|
@ -411,6 +465,7 @@ ebpf_map_function_table_t ebpf_map_function_tables[] = {
|
|||
{// BPF_MAP_TYPE_PROG_ARRAY
|
||||
_create_prog_array_map,
|
||||
_delete_array_map_with_references,
|
||||
_associate_program_with_prog_array_map,
|
||||
_find_array_map_entry,
|
||||
_get_object_from_array_map_entry,
|
||||
NULL,
|
||||
|
@ -426,10 +481,10 @@ ebpf_map_create(
|
|||
_Outptr_ ebpf_map_t** ebpf_map)
|
||||
{
|
||||
ebpf_map_t* local_map = NULL;
|
||||
size_t type = ebpf_map_definition->type;
|
||||
ebpf_map_type_t type = ebpf_map_definition->type;
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
|
||||
if (ebpf_map_definition->type >= EBPF_COUNT_OF(ebpf_map_function_tables)) {
|
||||
if (type >= EBPF_COUNT_OF(ebpf_map_function_tables)) {
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
goto Exit;
|
||||
}
|
||||
|
@ -478,6 +533,14 @@ ebpf_map_find_entry(_In_ ebpf_map_t* map, _In_ const uint8_t* key, int flags)
|
|||
return ebpf_map_function_tables[map->ebpf_map_definition.type].find_entry(map, key);
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_map_associate_program(_In_ ebpf_map_t* map, _In_ const ebpf_program_t* program)
|
||||
{
|
||||
if (ebpf_map_function_tables[map->ebpf_map_definition.type].associate_program)
|
||||
return ebpf_map_function_tables[map->ebpf_map_definition.type].associate_program(map, program);
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
_Ret_maybenull_ ebpf_program_t*
|
||||
ebpf_map_get_program_from_entry(_In_ ebpf_map_t* map, _In_ const uint8_t* key, size_t key_size)
|
||||
{
|
||||
|
|
|
@ -118,6 +118,19 @@ extern "C"
|
|||
_Ret_maybenull_ struct _ebpf_program*
|
||||
ebpf_map_get_program_from_entry(_In_ ebpf_map_t* map, _In_ const uint8_t* key, size_t key_size);
|
||||
|
||||
/**
|
||||
* @brief Let a map take any actions when first
|
||||
* associated with a program.
|
||||
*
|
||||
* @param[in] map Map to update.
|
||||
* @param[in] program Program being associated with.
|
||||
*
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_INVALID_FD The program is incompatible with this map.
|
||||
*/
|
||||
ebpf_result_t
|
||||
ebpf_map_associate_program(_In_ ebpf_map_t* map, _In_ const struct _ebpf_program* program);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -315,24 +315,46 @@ Done:
|
|||
return return_value;
|
||||
}
|
||||
|
||||
void
|
||||
ebpf_program_get_properties(ebpf_program_t* program, ebpf_program_parameters_t* program_parameters)
|
||||
_Ret_notnull_ const ebpf_program_parameters_t*
|
||||
ebpf_program_get_parameters(_In_ const ebpf_program_t* program)
|
||||
{
|
||||
*program_parameters = program->parameters;
|
||||
return &program->parameters;
|
||||
}
|
||||
|
||||
_Ret_notnull_ const ebpf_program_type_t*
|
||||
ebpf_program_type(_In_ const ebpf_program_t* program)
|
||||
{
|
||||
return &ebpf_program_get_parameters(program)->program_type;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_program_associate_maps(ebpf_program_t* program, ebpf_map_t** maps, size_t maps_count)
|
||||
{
|
||||
size_t index;
|
||||
program->maps = ebpf_allocate(maps_count * sizeof(ebpf_map_t*));
|
||||
if (!program->maps)
|
||||
ebpf_map_t** program_maps = ebpf_allocate(maps_count * sizeof(ebpf_map_t*));
|
||||
if (!program_maps)
|
||||
return EBPF_NO_MEMORY;
|
||||
|
||||
memcpy(program->maps, maps, sizeof(ebpf_map_t*) * maps_count);
|
||||
memcpy(program_maps, maps, sizeof(ebpf_map_t*) * maps_count);
|
||||
|
||||
// Before we acquire any references, map sure
|
||||
// all maps can be associated.
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
for (index = 0; index < maps_count; index++) {
|
||||
ebpf_map_t* map = program_maps[index];
|
||||
result = ebpf_map_associate_program(map, program);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
ebpf_free(program_maps);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Now go through again and acquire references.
|
||||
program->maps = program_maps;
|
||||
program->count_of_maps = maps_count;
|
||||
for (index = 0; index < program->count_of_maps; index++)
|
||||
ebpf_object_acquire_reference((ebpf_object_t*)program->maps[index]);
|
||||
for (index = 0; index < maps_count; index++) {
|
||||
ebpf_object_acquire_reference((ebpf_object_t*)program_maps[index]);
|
||||
}
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -60,13 +60,16 @@ extern "C"
|
|||
ebpf_program_initialize(ebpf_program_t* program, const ebpf_program_parameters_t* program_parameters);
|
||||
|
||||
/**
|
||||
* @brief Get properties describing the program instance.
|
||||
* @brief Get parameters describing the program instance.
|
||||
*
|
||||
* @param[in] program Program instance to query.
|
||||
* @param[out] program_parameters Parameters of the program.
|
||||
* @returns Pointer to parameters of the program.
|
||||
*/
|
||||
void
|
||||
ebpf_program_get_properties(ebpf_program_t* program, ebpf_program_parameters_t* program_parameters);
|
||||
_Ret_notnull_ const ebpf_program_parameters_t*
|
||||
ebpf_program_get_parameters(_In_ const ebpf_program_t* program);
|
||||
|
||||
_Ret_notnull_ const ebpf_program_type_t*
|
||||
ebpf_program_type(_In_ const ebpf_program_t* program);
|
||||
|
||||
/**
|
||||
* @brief Get the program info from the program info extension.
|
||||
|
|
|
@ -133,17 +133,13 @@ TEST_CASE("program", "[execution_context]")
|
|||
program_info_provider_t program_info_provider(EBPF_PROGRAM_TYPE_BIND);
|
||||
|
||||
const ebpf_program_parameters_t program_parameters{EBPF_PROGRAM_TYPE_BIND, program_name, section_name};
|
||||
ebpf_program_parameters_t returned_program_parameters{};
|
||||
ebpf_program_info_t* program_info;
|
||||
|
||||
REQUIRE(ebpf_program_initialize(program.get(), &program_parameters) == EBPF_SUCCESS);
|
||||
|
||||
ebpf_program_get_properties(program.get(), &returned_program_parameters);
|
||||
const ebpf_program_type_t* returned_program_type = ebpf_program_type(program.get());
|
||||
REQUIRE(
|
||||
memcmp(
|
||||
&program_parameters.program_type,
|
||||
&returned_program_parameters.program_type,
|
||||
sizeof(program_parameters.program_type)) == 0);
|
||||
memcmp(&program_parameters.program_type, returned_program_type, sizeof(program_parameters.program_type)) == 0);
|
||||
|
||||
REQUIRE(ebpf_program_get_program_info(program.get(), &program_info) == EBPF_SUCCESS);
|
||||
REQUIRE(program_info != nullptr);
|
||||
|
|
|
@ -235,8 +235,8 @@ static ebpf_helper_function_prototype_t _helper_functions[] = {
|
|||
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
|
||||
{4,
|
||||
"bpf_tail_call",
|
||||
EBPF_RETURN_TYPE_INTEGER,
|
||||
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_ANYTHING}},
|
||||
EBPF_RETURN_TYPE_INTEGER_OR_NO_RETURN_IF_SUCCEED,
|
||||
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_OF_PROGRAMS, EBPF_ARGUMENT_TYPE_ANYTHING}},
|
||||
};
|
||||
|
||||
TEST_CASE("program_type_info", "[platform]")
|
||||
|
|
|
@ -146,8 +146,8 @@ static ebpf_helper_function_prototype_t _ebpf_map_helper_function_prototype[] =
|
|||
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
|
||||
{4,
|
||||
"bpf_tail_call",
|
||||
EBPF_RETURN_TYPE_INTEGER,
|
||||
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_ANYTHING}},
|
||||
EBPF_RETURN_TYPE_INTEGER_OR_NO_RETURN_IF_SUCCEED,
|
||||
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_OF_PROGRAMS, EBPF_ARGUMENT_TYPE_ANYTHING}},
|
||||
};
|
||||
|
||||
static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {sizeof(xdp_md_t),
|
||||
|
|
|
@ -72,14 +72,16 @@ TEST_CASE("libbpf program pinning", "[libbpf]")
|
|||
|
||||
// Make sure a duplicate pin fails.
|
||||
result = bpf_program__pin(program, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
result = bpf_program__unpin(program, pin_path);
|
||||
REQUIRE(result == 0);
|
||||
|
||||
// Make sure a duplicate unpin fails.
|
||||
result = bpf_program__unpin(program, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
// Try to pin all (1) programs in the object.
|
||||
result = bpf_object__pin_programs(object, pin_path);
|
||||
|
@ -87,7 +89,8 @@ TEST_CASE("libbpf program pinning", "[libbpf]")
|
|||
|
||||
// Make sure a duplicate pin fails.
|
||||
result = bpf_object__pin_programs(object, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
result = bpf_object__unpin_programs(object, pin_path);
|
||||
REQUIRE(result == 0);
|
||||
|
@ -98,7 +101,8 @@ TEST_CASE("libbpf program pinning", "[libbpf]")
|
|||
|
||||
// Make sure a duplicate pin fails.
|
||||
result = bpf_object__pin_programs(object, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
// There is no bpf_object__unpin API, so
|
||||
// we have to unpin programs and maps separately.
|
||||
|
@ -144,7 +148,8 @@ TEST_CASE("libbpf program attach", "[libbpf]")
|
|||
|
||||
// Verify that a duplicate link destroy fails.
|
||||
result = bpf_link__destroy(link);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
bpf_object__close(object);
|
||||
}
|
||||
|
@ -203,7 +208,8 @@ TEST_CASE("libbpf map pinning", "[libbpf]")
|
|||
|
||||
// Make sure a duplicate pin fails.
|
||||
result = bpf_map__pin(map, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
result = bpf_map__unpin(map, pin_path);
|
||||
REQUIRE(result == 0);
|
||||
|
@ -212,7 +218,8 @@ TEST_CASE("libbpf map pinning", "[libbpf]")
|
|||
|
||||
// Make sure a duplicate unpin fails.
|
||||
result = bpf_map__unpin(map, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
// Clear pin path for the map.
|
||||
result = bpf_map__set_pin_path(map, nullptr);
|
||||
|
@ -226,7 +233,8 @@ TEST_CASE("libbpf map pinning", "[libbpf]")
|
|||
|
||||
// Make sure a duplicate pin fails.
|
||||
result = bpf_object__pin_maps(object, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
result = bpf_object__unpin_maps(object, pin_path);
|
||||
REQUIRE(result == 0);
|
||||
|
@ -241,7 +249,8 @@ TEST_CASE("libbpf map pinning", "[libbpf]")
|
|||
|
||||
// Make sure a duplicate pin fails.
|
||||
result = bpf_object__pin_maps(object, pin_path);
|
||||
REQUIRE(result != 0);
|
||||
REQUIRE(result < 0);
|
||||
REQUIRE(errno == -result);
|
||||
|
||||
// There is no bpf_object__unpin API, so
|
||||
// we have to unpin programs and maps separately.
|
||||
|
@ -286,16 +295,18 @@ _ebpf_test_tail_call(_In_z_ const char* filename, int expected_result)
|
|||
|
||||
// First do some negative tests.
|
||||
int index = 1;
|
||||
int err = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&callee_fd, 0);
|
||||
REQUIRE(err != 0);
|
||||
error = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&callee_fd, 0);
|
||||
REQUIRE(error < 0);
|
||||
REQUIRE(errno == -error);
|
||||
index = 0;
|
||||
int bad_fd = 0;
|
||||
err = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&bad_fd, 0);
|
||||
REQUIRE(err != 0);
|
||||
error = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&bad_fd, 0);
|
||||
REQUIRE(error < 0);
|
||||
REQUIRE(errno == -error);
|
||||
|
||||
// Finally store the correct program fd.
|
||||
err = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&callee_fd, 0);
|
||||
REQUIRE(err == 0);
|
||||
error = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&callee_fd, 0);
|
||||
REQUIRE(error == 0);
|
||||
|
||||
bpf_link* link = bpf_program__attach_xdp(caller, 1);
|
||||
REQUIRE(link != nullptr);
|
||||
|
@ -319,3 +330,82 @@ TEST_CASE("good tail_call", "[libbpf]")
|
|||
}
|
||||
|
||||
TEST_CASE("bad tail_call", "[libbpf]") { _ebpf_test_tail_call("tail_call_bad.o", -EBPF_INVALID_ARGUMENT); }
|
||||
|
||||
TEST_CASE("disallow setting bind fd in xdp prog array", "[libbpf]")
|
||||
{
|
||||
_test_helper_end_to_end test_helper;
|
||||
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
|
||||
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
|
||||
|
||||
struct bpf_object* xdp_object;
|
||||
int xdp_object_fd;
|
||||
int error = bpf_prog_load("tail_call.o", BPF_PROG_TYPE_XDP, &xdp_object, &xdp_object_fd);
|
||||
REQUIRE(error == 0);
|
||||
REQUIRE(xdp_object != nullptr);
|
||||
|
||||
struct bpf_map* map = bpf_map__next(nullptr, xdp_object);
|
||||
REQUIRE(map != nullptr);
|
||||
|
||||
// Load a program of any other type.
|
||||
struct bpf_object* bind_object;
|
||||
int bind_object_fd;
|
||||
error = bpf_prog_load("bindmonitor.o", BPF_PROG_TYPE_BIND, &bind_object, &bind_object_fd);
|
||||
REQUIRE(error == 0);
|
||||
REQUIRE(bind_object != nullptr);
|
||||
|
||||
struct bpf_program* callee = bpf_object__find_program_by_name(bind_object, "BindMonitor");
|
||||
REQUIRE(callee != nullptr);
|
||||
|
||||
int callee_fd = bpf_program__fd(callee);
|
||||
REQUIRE(callee_fd >= 0);
|
||||
|
||||
int map_fd = bpf_map__fd(map);
|
||||
REQUIRE(map_fd >= 0);
|
||||
|
||||
// Verify that we cannot add a BIND program fd to a prog_array map already
|
||||
// associated with an XDP program.
|
||||
int index = 0;
|
||||
error = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&callee_fd, 0);
|
||||
REQUIRE(error < 0);
|
||||
REQUIRE(errno == -error);
|
||||
|
||||
bpf_object__close(bind_object);
|
||||
bpf_object__close(xdp_object);
|
||||
}
|
||||
|
||||
TEST_CASE("disallow prog_array mixed program type values", "[libbpf]")
|
||||
{
|
||||
_test_helper_end_to_end test_helper;
|
||||
program_info_provider_t bind_program_info(EBPF_PROGRAM_TYPE_BIND);
|
||||
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
|
||||
|
||||
struct bpf_object* xdp_object;
|
||||
int xdp_object_fd;
|
||||
int error = bpf_prog_load("droppacket.o", BPF_PROG_TYPE_XDP, &xdp_object, &xdp_object_fd);
|
||||
REQUIRE(error == 0);
|
||||
REQUIRE(xdp_object != nullptr);
|
||||
|
||||
struct bpf_object* bind_object;
|
||||
int bind_object_fd;
|
||||
error = bpf_prog_load("bindmonitor.o", BPF_PROG_TYPE_BIND, &bind_object, &bind_object_fd);
|
||||
REQUIRE(error == 0);
|
||||
REQUIRE(bind_object != nullptr);
|
||||
|
||||
// Create a map.
|
||||
int map_fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(uint32_t), sizeof(uint32_t), 2, 0);
|
||||
REQUIRE(map_fd > 0);
|
||||
|
||||
// Since the map is not yet associated with a program, the first program fd
|
||||
// we add will become the PROG_ARRAY's program type.
|
||||
int index = 0;
|
||||
error = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&xdp_object_fd, 0);
|
||||
REQUIRE(error == 0);
|
||||
|
||||
// Adding an entry with a different program type should fail.
|
||||
error = bpf_map_update_elem(map_fd, (uint8_t*)&index, (uint8_t*)&bind_object_fd, 0);
|
||||
REQUIRE(error < 0);
|
||||
REQUIRE(errno == -error);
|
||||
|
||||
bpf_object__close(bind_object);
|
||||
bpf_object__close(xdp_object);
|
||||
}
|
||||
|
|
|
@ -46,8 +46,8 @@ static ebpf_helper_function_prototype_t _ebpf_helper_function_prototype[] = {
|
|||
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}},
|
||||
{4,
|
||||
"bpf_tail_call",
|
||||
EBPF_RETURN_TYPE_INTEGER,
|
||||
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_ANYTHING}}};
|
||||
EBPF_RETURN_TYPE_INTEGER_OR_NO_RETURN_IF_SUCCEED,
|
||||
{EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_OF_PROGRAMS, EBPF_ARGUMENT_TYPE_ANYTHING}}};
|
||||
|
||||
static ebpf_result_t
|
||||
_encode_bind()
|
||||
|
|
Загрузка…
Ссылка в новой задаче