Fix calling ObReferenceObjectByHandle at DISPATCH (#840)

* bugfix, add test cases

* fix build break

* cr comments

* cr comments

* cr comments
This commit is contained in:
saxena-anurag 2022-03-28 10:25:12 -07:00 коммит произвёл GitHub
Родитель afe3452b4e
Коммит edd6d974d5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 115 добавлений и 33 удалений

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

@ -496,20 +496,13 @@ _check_value_type(_In_ const ebpf_core_map_t* outer_map, _In_ const ebpf_core_ob
return allowed;
}
// Validate that a value handle is appropriate for this map,
// and if so, return a pointer to the object with that handle.
static ebpf_result_t
_get_map_value_object(
_In_ const ebpf_core_map_t* map,
ebpf_handle_t value_handle,
ebpf_object_type_t value_type,
_Outptr_ ebpf_core_object_t** value_object_result)
// Validate that a value object is appropriate for this map.
// Also set the program type if not yet set.
static _Requires_lock_held_(object_map->lock) ebpf_result_t _validate_map_value_object(
_In_ ebpf_core_object_map_t* object_map, ebpf_object_type_t value_type, _In_ const ebpf_core_object_t* value_object)
{
// Convert value handle to an object pointer.
ebpf_core_object_t* value_object = NULL;
ebpf_result_t result = ebpf_reference_object_by_handle(value_handle, value_type, &value_object);
if (result != EBPF_SUCCESS)
return result;
ebpf_result_t result = EBPF_SUCCESS;
const ebpf_core_map_t* map = &object_map->core_map;
const ebpf_program_type_t* value_program_type =
(value_object->get_program_type) ? value_object->get_program_type(value_object) : NULL;
@ -525,21 +518,18 @@ _get_map_value_object(
// Validate that the value's program type (if any) is
// not in conflict with the map's program type.
if (value_program_type != NULL) {
ebpf_core_object_map_t* map_of_objects = (ebpf_core_object_map_t*)map;
if (!map_of_objects->is_program_type_set) {
map_of_objects->is_program_type_set = TRUE;
map_of_objects->program_type = *value_program_type;
} else if (memcmp(&map_of_objects->program_type, value_program_type, sizeof(*value_program_type)) != 0) {
if (!object_map->is_program_type_set) {
object_map->is_program_type_set = TRUE;
object_map->program_type = *value_program_type;
} else if (memcmp(&object_map->program_type, value_program_type, sizeof(*value_program_type)) != 0) {
result = EBPF_INVALID_FD;
goto Error;
}
}
*value_object_result = value_object;
return EBPF_SUCCESS;
Error:
ebpf_object_release_reference((ebpf_core_object_t*)value_object);
return result;
}
@ -562,14 +552,19 @@ _update_array_map_entry_with_handle(
ebpf_result_t result = EBPF_SUCCESS;
ebpf_core_object_map_t* object_map = EBPF_FROM_FIELD(ebpf_core_object_map_t, core_map, map);
ebpf_core_object_t* value_object = NULL;
if (value_handle != (uintptr_t)ebpf_handle_invalid) {
result = ebpf_reference_object_by_handle(value_handle, value_type, &value_object);
if (result != EBPF_SUCCESS) {
return result;
}
}
ebpf_lock_state_t lock_state = ebpf_lock_lock(&object_map->lock);
ebpf_core_object_t* value_object = NULL;
// If value_handle is valid, resolve it to an object. Else we just need to clear
// the existing entry from the map.
if (value_handle != (uintptr_t)ebpf_handle_invalid) {
result = _get_map_value_object(map, value_handle, value_type, &value_object);
result = _validate_map_value_object(object_map, value_type, value_object);
if (result != EBPF_SUCCESS) {
goto Done;
}
@ -588,6 +583,9 @@ _update_array_map_entry_with_handle(
memcpy(entry, &id, map->ebpf_map_definition.value_size);
Done:
if (result != EBPF_SUCCESS && value_object != NULL) {
ebpf_object_release_reference((ebpf_core_object_t*)value_object);
}
ebpf_lock_unlock(&object_map->lock, lock_state);
return result;
@ -1063,6 +1061,11 @@ _update_hash_map_entry_with_handle(
}
ebpf_core_object_map_t* object_map = EBPF_FROM_FIELD(ebpf_core_object_map_t, core_map, map);
ebpf_core_object_t* value_object = NULL;
result = ebpf_reference_object_by_handle(value_handle, value_type, &value_object);
if (result != EBPF_SUCCESS) {
return result;
}
ebpf_lock_state_t lock_state = ebpf_lock_lock(&object_map->lock);
@ -1071,7 +1074,6 @@ _update_hash_map_entry_with_handle(
uint8_t* old_value = NULL;
ebpf_result_t found_result = ebpf_hash_table_find((ebpf_hash_table_t*)map->data, key, &old_value);
ebpf_id_t old_id = (old_value) ? *(ebpf_id_t*)old_value : 0;
ebpf_core_object_t* value_object = NULL;
if ((entry_count == map->ebpf_map_definition.max_entries) && (found_result != EBPF_SUCCESS)) {
// The hash table is already full.
@ -1079,7 +1081,7 @@ _update_hash_map_entry_with_handle(
goto Done;
}
result = _get_map_value_object(map, value_handle, value_type, &value_object);
result = _validate_map_value_object(object_map, value_type, value_object);
if (result != EBPF_SUCCESS) {
goto Done;
}

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

@ -59,9 +59,8 @@ extern "C"
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_OBJECT The provided handle is not valid.
*/
ebpf_result_t
ebpf_reference_object_by_handle(
ebpf_handle_t handle, ebpf_object_type_t object_type, struct _ebpf_core_object** object);
_IRQL_requires_max_(PASSIVE_LEVEL) ebpf_result_t ebpf_reference_object_by_handle(
ebpf_handle_t handle, ebpf_object_type_t object_type, _Outptr_ struct _ebpf_core_object** object);
#ifdef __cplusplus
}

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

@ -87,8 +87,8 @@ ebpf_handle_close(ebpf_handle_t handle)
EBPF_RETURN_RESULT(EBPF_SUCCESS);
}
ebpf_result_t
ebpf_reference_object_by_handle(ebpf_handle_t handle, ebpf_object_type_t object_type, ebpf_core_object_t** object)
_IRQL_requires_max_(PASSIVE_LEVEL) ebpf_result_t ebpf_reference_object_by_handle(
ebpf_handle_t handle, ebpf_object_type_t object_type, _Outptr_ ebpf_core_object_t** object)
{
ebpf_result_t return_value;
NTSTATUS status;

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

@ -84,8 +84,8 @@ ebpf_handle_close(ebpf_handle_t handle)
return return_value;
}
ebpf_result_t
ebpf_reference_object_by_handle(ebpf_handle_t handle, ebpf_object_type_t object_type, ebpf_core_object_t** object)
_IRQL_requires_max_(PASSIVE_LEVEL) ebpf_result_t ebpf_reference_object_by_handle(
ebpf_handle_t handle, ebpf_object_type_t object_type, _Outptr_ ebpf_core_object_t** object)
{
ebpf_result_t return_value;
ebpf_lock_state_t state;

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

@ -314,3 +314,84 @@ TEST_CASE("divide_by_zero_jit", "[divide_by_zero]") { divide_by_zero_test_km(EBP
TEST_CASE("ringbuf_api_interpret", "[test_ringbuf_api]") { ring_buffer_api_test(EBPF_EXECUTION_INTERPRET); }
TEST_CASE("divide_by_zero_interpret", "[divide_by_zero]") { divide_by_zero_test_km(EBPF_EXECUTION_INTERPRET); }
#endif
void
_test_nested_maps(bpf_map_type type)
{
// Create first inner map.
fd_t inner1 = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(uint32_t), sizeof(uint32_t), 1, 0);
REQUIRE(inner1 > 0);
// Create outer map.
fd_t outer_map_fd = bpf_create_map_in_map(type, "outer_map", sizeof(uint32_t), inner1, 10, 0);
REQUIRE(outer_map_fd > 0);
// Create second inner map.
fd_t inner2 = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(uint32_t), sizeof(uint32_t), 1, 0);
REQUIRE(inner2 > 0);
// Insert both inner maps in outer map.
uint32_t key = 1;
uint32_t result = bpf_map_update_elem(outer_map_fd, &key, &inner1, 0);
REQUIRE(result == ERROR_SUCCESS);
key = 2;
result = bpf_map_update_elem(outer_map_fd, &key, &inner1, 0);
REQUIRE(result == ERROR_SUCCESS);
// Remove the inner maps from outer map.
key = 1;
result = bpf_map_delete_elem(outer_map_fd, &key);
REQUIRE(result == ERROR_SUCCESS);
key = 2;
result = bpf_map_delete_elem(outer_map_fd, &key);
REQUIRE(result == ERROR_SUCCESS);
_close(inner1);
_close(inner2);
_close(outer_map_fd);
}
TEST_CASE("array_of_maps", "[map_in_map]") { _test_nested_maps(BPF_MAP_TYPE_ARRAY_OF_MAPS); }
TEST_CASE("hash_of_maps", "[map_in_map]") { _test_nested_maps(BPF_MAP_TYPE_HASH_OF_MAPS); }
TEST_CASE("tailcall_load_test", "[tailcall_load_test]")
{
ebpf_result_t result;
struct bpf_object* object = nullptr;
fd_t program_fd;
result =
_program_load_helper("tail_call_multiple.o", &EBPF_PROGRAM_TYPE_XDP, EBPF_EXECUTION_ANY, &object, &program_fd);
REQUIRE(result == EBPF_SUCCESS);
REQUIRE(program_fd > 0);
// Set up tail calls.
struct bpf_program* callee0 = bpf_object__find_program_by_name(object, "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, "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, "map");
REQUIRE(prog_map_fd > 0);
uint32_t index = 0;
REQUIRE(bpf_map_update_elem(prog_map_fd, &index, &callee0_fd, 0) == 0);
index = 1;
REQUIRE(bpf_map_update_elem(prog_map_fd, &index, &callee1_fd, 0) == 0);
// Cleanup tail calls.
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);
}