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:
Dave Thaler 2021-08-11 12:17:10 -07:00 коммит произвёл GitHub
Родитель 014ee34392
Коммит 7c12adb067
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 283 добавлений и 72 удалений

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

@ -5,6 +5,7 @@
LIBRARY
EXPORTS
bpf_create_map
bpf_link__destroy
bpf_link__pin
bpf_link__unpin

2
external/ebpf-verifier поставляемый

@ -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, &parameters);
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()