Instrument all allocation paths (#1620)

* Instrument all allocation paths

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Fix test failure

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Remove global new/delete until issue can be resolved

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Fix code analysis warning

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Revert ubpf update

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Code analysis failure

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* PR feedback

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Fix code-analysis warning

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Fix code-analysis warning

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Fix codeanalysis failures

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* PR feedback

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

Signed-off-by: Alan Jowett <alanjo@microsoft.com>
Co-authored-by: Anurag Saxena <43585259+saxena-anurag@users.noreply.github.com>
Co-authored-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Alan Jowett 2022-11-19 16:33:27 +00:00 коммит произвёл GitHub
Родитель 0a9be2779e
Коммит 0e3f2a5157
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 108 добавлений и 74 удалений

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

@ -216,7 +216,7 @@ load_byte_code(
}
for (auto& raw_program : raw_programs) {
program = (ebpf_program_t*)calloc(1, sizeof(ebpf_program_t));
program = (ebpf_program_t*)ebpf_allocate(sizeof(ebpf_program_t));
if (program == nullptr) {
result = EBPF_NO_MEMORY;
goto Exit;
@ -235,7 +235,7 @@ load_byte_code(
goto Exit;
}
size_t ebpf_bytes = instruction_count * sizeof(ebpf_inst);
program->instructions = (ebpf_inst*)calloc(1, ebpf_bytes);
program->instructions = (ebpf_inst*)ebpf_allocate(ebpf_bytes);
if (program->instructions == nullptr) {
result = EBPF_NO_MEMORY;
goto Exit;
@ -288,7 +288,7 @@ load_byte_code(
goto Exit;
}
map = (ebpf_map_t*)calloc(1, sizeof(ebpf_map_t));
map = (ebpf_map_t*)ebpf_allocate(sizeof(ebpf_map_t));
if (map == nullptr) {
result = EBPF_NO_MEMORY;
goto Exit;
@ -328,7 +328,7 @@ load_byte_code(
} catch (std::runtime_error& err) {
auto message = err.what();
auto message_length = strlen(message) + 1;
char* error = reinterpret_cast<char*>(calloc(message_length + 1, sizeof(char)));
char* error = reinterpret_cast<char*>(ebpf_allocate(message_length + 1));
if (error) {
strcpy_s(error, message_length, message);
}
@ -361,13 +361,13 @@ Exit:
static void
_ebpf_add_stat(_Inout_ ebpf_section_info_t* info, std::string key, int value) noexcept(false)
{
ebpf_stat_t* stat = (ebpf_stat_t*)malloc(sizeof(*stat));
ebpf_stat_t* stat = (ebpf_stat_t*)ebpf_allocate(sizeof(*stat));
if (stat == nullptr) {
throw std::runtime_error("Out of memory");
}
stat->key = _strdup(key.c_str());
if (stat->key == nullptr) {
free(stat);
ebpf_free(stat);
throw std::runtime_error("Out of memory");
}
stat->value = value;
@ -394,7 +394,7 @@ ebpf_api_elf_enumerate_sections(
try {
auto raw_programs = read_elf(file, section ? std::string(section) : std::string(), &verifier_options, platform);
for (const auto& raw_program : raw_programs) {
ebpf_section_info_t* info = (ebpf_section_info_t*)malloc(sizeof(*info));
ebpf_section_info_t* info = (ebpf_section_info_t*)ebpf_allocate(sizeof(*info));
if (info == nullptr) {
throw std::runtime_error("Out of memory");
}
@ -404,7 +404,7 @@ ebpf_api_elf_enumerate_sections(
std::variant<InstructionSeq, std::string> programOrError = unmarshal(raw_program);
if (std::holds_alternative<std::string>(programOrError)) {
std::cout << "parse failure: " << std::get<std::string>(programOrError) << "\n";
free(info);
ebpf_free(info);
return 1;
}
auto& program = std::get<InstructionSeq>(programOrError);
@ -421,12 +421,12 @@ ebpf_api_elf_enumerate_sections(
std::vector<uint8_t> raw_data = convert_ebpf_program_to_bytes(raw_program.prog);
info->raw_data_size = raw_data.size();
info->raw_data = (char*)malloc(info->raw_data_size);
info->raw_data = (char*)ebpf_allocate(info->raw_data_size);
if (info->raw_data == nullptr || info->section_name == nullptr || info->program_type_name == nullptr) {
free((void*)info->section_name);
free((void*)info->program_type_name);
free((void*)info->raw_data);
free(info);
ebpf_free((void*)info->section_name);
ebpf_free((void*)info->program_type_name);
ebpf_free((void*)info->raw_data);
ebpf_free(info);
throw std::runtime_error("Out of memory");
}
memcpy(info->raw_data, raw_data.data(), info->raw_data_size);

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

@ -760,7 +760,7 @@ void
ebpf_free_string(_In_opt_ _Post_invalid_ const char* error_message)
{
EBPF_LOG_ENTRY();
free(const_cast<char*>(error_message));
ebpf_free(const_cast<char*>(error_message));
EBPF_LOG_EXIT();
}
@ -830,7 +830,7 @@ ebpf_map_pin(_In_ struct bpf_map* map, _In_opt_z_ const char* path) noexcept
if (map->pin_path != nullptr && strcmp(path, map->pin_path) != 0) {
EBPF_RETURN_RESULT(EBPF_INVALID_ARGUMENT);
}
free(map->pin_path);
ebpf_free(map->pin_path);
map->pin_path = _strdup(path);
if (map->pin_path == nullptr) {
EBPF_RETURN_RESULT(EBPF_NO_MEMORY);
@ -859,7 +859,7 @@ ebpf_map_set_pin_path(_In_ struct bpf_map* map, _In_opt_z_ const char* path) noe
}
}
map->pin_path = const_cast<char*>(path);
free(old_path);
ebpf_free(old_path);
EBPF_RETURN_RESULT(EBPF_SUCCESS);
}
@ -952,12 +952,12 @@ ebpf_program_query_info(
size_t file_name_length = reply->section_name_offset - reply->file_name_offset;
size_t section_name_length = reply->header.length - reply->section_name_offset;
char* local_file_name = reinterpret_cast<char*>(calloc(file_name_length + 1, sizeof(char)));
char* local_section_name = reinterpret_cast<char*>(calloc(section_name_length + 1, sizeof(char)));
char* local_file_name = reinterpret_cast<char*>(ebpf_allocate(file_name_length + 1));
char* local_section_name = reinterpret_cast<char*>(ebpf_allocate(section_name_length + 1));
if (!local_file_name || !local_section_name) {
free(local_file_name);
free(local_section_name);
ebpf_free(local_file_name);
ebpf_free(local_section_name);
EBPF_RETURN_RESULT(EBPF_NO_MEMORY);
}
@ -994,7 +994,7 @@ _link_ebpf_program(
ebpf_assert(attach_parameter || !attach_parameter_size);
*link = nullptr;
ebpf_link_t* new_link = (ebpf_link_t*)calloc(1, sizeof(ebpf_link_t));
ebpf_link_t* new_link = (ebpf_link_t*)ebpf_allocate(sizeof(ebpf_link_t));
if (new_link == nullptr) {
EBPF_RETURN_RESULT(EBPF_NO_MEMORY);
}
@ -1061,10 +1061,8 @@ _clean_up_ebpf_link(_Frees_ptr_opt_ ebpf_link_t* link) noexcept
if (link->fd != ebpf_fd_invalid) {
Platform::_close(link->fd);
}
free(link->pin_path);
free(link);
ebpf_free(link->pin_path);
ebpf_free(link);
#pragma warning(pop)
EBPF_RETURN_VOID();
}
@ -1354,12 +1352,12 @@ clean_up_ebpf_program(_In_ _Post_invalid_ ebpf_program_t* program) noexcept
ebpf_assert(program);
ebpf_assert_success(ebpf_program_unload(program));
free(program->instructions);
free(program->program_name);
free(program->section_name);
free((void*)program->log_buffer);
ebpf_free(program->instructions);
ebpf_free(program->program_name);
ebpf_free(program->section_name);
ebpf_free((void*)program->log_buffer);
free(program);
ebpf_free(program);
}
void
@ -1383,10 +1381,10 @@ clean_up_ebpf_map(_In_ _Post_invalid_ ebpf_map_t* map) noexcept
if (map->map_handle != ebpf_handle_invalid) {
_ebpf_maps.erase(map->map_handle);
}
free(map->name);
free(map->pin_path);
ebpf_free(map->name);
ebpf_free(map->pin_path);
free(map);
ebpf_free(map);
}
void
@ -1407,8 +1405,8 @@ _clean_up_ebpf_object(_In_opt_ ebpf_object_t* object) noexcept
clean_up_ebpf_programs(object->programs);
clean_up_ebpf_maps(object->maps);
free(object->object_name);
free(object->file_name);
ebpf_free(object->object_name);
ebpf_free(object->file_name);
}
}
@ -1645,7 +1643,7 @@ _initialize_ebpf_object_from_native_file(
object.execution_type = EBPF_EXECUTION_NATIVE;
for (ebpf_section_info_t* info = infos; info; info = info->next) {
program = (ebpf_program_t*)calloc(1, sizeof(ebpf_program_t));
program = (ebpf_program_t*)ebpf_allocate(sizeof(ebpf_program_t));
if (program == nullptr) {
result = EBPF_NO_MEMORY;
goto Exit;
@ -1680,7 +1678,7 @@ _initialize_ebpf_object_from_native_file(
}
Exit:
free(program);
ebpf_free(program);
if (result != EBPF_SUCCESS) {
clean_up_ebpf_programs(object.programs);
clean_up_ebpf_maps(object.maps);
@ -1825,15 +1823,15 @@ _ebpf_free_section_info(_In_ _Frees_ptr_ ebpf_section_info_t* info) noexcept
#pragma warning(disable : 6001)
// MSVC incorrectly reports this as using uninitialized memory.
info->stats = stat->next;
free((void*)stat->key);
ebpf_free((void*)stat->key);
#pragma warning(pop)
free(stat);
ebpf_free(stat);
}
free((void*)info->program_name);
free((void*)info->section_name);
free((void*)info->program_type_name);
free(info->raw_data);
free(info);
ebpf_free((void*)info->program_name);
ebpf_free((void*)info->section_name);
ebpf_free((void*)info->program_type_name);
ebpf_free(info->raw_data);
ebpf_free(info);
EBPF_LOG_EXIT();
}
@ -1906,7 +1904,7 @@ _ebpf_pe_get_map_definitions(
break;
}
map = (ebpf_map_t*)calloc(1, sizeof(ebpf_map_t));
map = (ebpf_map_t*)ebpf_allocate(sizeof(ebpf_map_t));
if (map == nullptr) {
goto Error;
}
@ -2079,7 +2077,7 @@ _ebpf_pe_add_section(
std::string elf_section_name = pe_context->section_names[pe_section_name];
std::string program_name = pe_context->program_names[pe_section_name];
ebpf_section_info_t* info = (ebpf_section_info_t*)malloc(sizeof(*info));
ebpf_section_info_t* info = (ebpf_section_info_t*)ebpf_allocate(sizeof(*info));
if (info == nullptr) {
pe_context->result = EBPF_NO_MEMORY;
EBPF_LOG_EXIT();
@ -2099,7 +2097,7 @@ _ebpf_pe_add_section(
}
info->program_type_name = _strdup(info->program_type_name);
info->raw_data_size = section_header.Misc.VirtualSize;
info->raw_data = (char*)malloc(section_header.Misc.VirtualSize);
info->raw_data = (char*)ebpf_allocate(section_header.Misc.VirtualSize);
if (info->raw_data == nullptr || info->program_type_name == nullptr || info->section_name == nullptr) {
_ebpf_free_section_info(info);
EBPF_LOG_EXIT();
@ -2918,14 +2916,14 @@ _ebpf_program_load_native(
}
// Allocate buffer for program and map handles.
program_handles = (ebpf_handle_t*)calloc(count_of_programs, sizeof(ebpf_handle_t));
program_handles = (ebpf_handle_t*)ebpf_allocate(count_of_programs * sizeof(ebpf_handle_t));
if (program_handles == nullptr) {
result = EBPF_NO_MEMORY;
goto Done;
}
if (count_of_maps > 0) {
map_handles = (ebpf_handle_t*)calloc(count_of_maps, sizeof(ebpf_handle_t));
map_handles = (ebpf_handle_t*)ebpf_allocate(count_of_maps * sizeof(ebpf_handle_t));
if (map_handles == nullptr) {
result = EBPF_NO_MEMORY;
goto Done;
@ -2976,8 +2974,8 @@ Done:
Platform::_stop_service(service_handle);
}
free(map_handles);
free(program_handles);
ebpf_free(map_handles);
ebpf_free(program_handles);
// Workaround: Querying service status hydrates service reference count in SCM.
// This ensures that when _delete_service() is called, the service is marked

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

@ -20,7 +20,7 @@ bpf_link__pin(struct bpf_link* link, const char* path)
result = ebpf_object_pin(link->fd, link->pin_path);
if (result != EBPF_SUCCESS) {
free(link->pin_path);
ebpf_free(link->pin_path);
link->pin_path = nullptr;
}
@ -40,7 +40,7 @@ bpf_link__unpin(struct bpf_link* link)
return libbpf_result_err(result);
}
free(link->pin_path);
ebpf_free(link->pin_path);
link->pin_path = nullptr;
return 0;
}

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

@ -113,7 +113,7 @@ bpf_prog_load_deprecated(const char* file_name, enum bpf_prog_type type, struct
struct bpf_object* new_object;
ebpf_result_t result =
ebpf_object_open(file_name, nullptr, nullptr, program_type, nullptr, &new_object, &log_buffer);
free((void*)log_buffer);
ebpf_free((void*)log_buffer);
if (result != EBPF_SUCCESS) {
return libbpf_result_err(result);
}

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

@ -25,7 +25,7 @@ allocate_string(const std::string& string, uint32_t* length) noexcept
{
char* new_string;
size_t string_length = string.size() + 1;
new_string = (char*)malloc(string_length);
new_string = (char*)ebpf_allocate(string_length);
if (new_string != nullptr) {
strcpy_s(new_string, string_length, string.c_str());
if (length != nullptr) {

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

@ -742,11 +742,8 @@ handle_ebpf_show_programs(
std::cout << "# map IDs : " << info.nr_map_ids << "\n";
if (info.nr_map_ids > 0) {
ebpf_id_t* map_ids = (ebpf_id_t*)malloc(info.nr_map_ids * sizeof(ebpf_id_t));
if (map_ids == nullptr) {
break;
}
info.map_ids = (uintptr_t)map_ids;
std::vector<ebpf_id_t> map_ids(info.nr_map_ids);
info.map_ids = (uintptr_t)map_ids.data();
error = bpf_obj_get_info_by_fd(program_fd, &info, &info_size);
if (error < 0) {
break;
@ -755,8 +752,6 @@ handle_ebpf_show_programs(
for (uint32_t i = 1; i < info.nr_map_ids; i++) {
std::cout << " " << map_ids[i] << "\n";
}
free(map_ids);
}
std::cout << "# pinned paths : " << info.pinned_path_count << "\n";

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

@ -634,13 +634,15 @@ TEST_CASE("serialize_map_test", "[platform]")
}
// Serialize.
ebpf_result_t result = ebpf_serialize_internal_map_info_array(
map_count, internal_map_info_array, buffer, buffer_length, &serialized_length, &required_length);
REQUIRE(result == EBPF_INSUFFICIENT_BUFFER);
REQUIRE(
ebpf_serialize_internal_map_info_array(
map_count, internal_map_info_array, buffer, buffer_length, &serialized_length, &required_length) ==
EBPF_INSUFFICIENT_BUFFER);
buffer = static_cast<uint8_t*>(calloc(required_length, 1));
REQUIRE(buffer != nullptr);
if (!buffer) {
buffer = static_cast<uint8_t*>(ebpf_allocate(required_length));
// Required to deal with code analysis warning about buffer not being checked for null.
if (buffer == nullptr) {
REQUIRE(false);
return;
}
buffer_length = required_length;
@ -699,8 +701,12 @@ TEST_CASE("serialize_program_info_test", "[platform]")
// Serialize.
REQUIRE(ebpf_serialize_program_info(&in_program_info, buffer, buffer_length, &serialized_length, &required_length));
buffer = static_cast<uint8_t*>(calloc(required_length, 1));
_Analysis_assume_(buffer != nullptr);
buffer = static_cast<uint8_t*>(ebpf_allocate(required_length));
// Work around code analysis warning about buffer not being checked for null.
if (buffer == nullptr) {
REQUIRE(false);
return;
}
buffer_length = required_length;
REQUIRE(

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

@ -29,6 +29,31 @@
#define EBPF_MODULE_SIZE_IN_BYTES (10 * 1024 * 1024)
/**
* @brief Thread local storage to track recursing from the low memory callback.
*/
static thread_local int _ebpf_low_memory_test_recursion = 0;
/**
* @brief Class to automatically increment and decrement the recursion count.
*/
class ebpf_low_memory_test_recursion_guard
{
public:
ebpf_low_memory_test_recursion_guard() { _ebpf_low_memory_test_recursion++; }
~ebpf_low_memory_test_recursion_guard() { _ebpf_low_memory_test_recursion--; }
/**
* @brief Return true if the current thread is recursing from the low memory callback.
* @retval true
* @retval false
*/
bool
is_recursing()
{
return (_ebpf_low_memory_test_recursion > 1);
}
};
_ebpf_low_memory_test::_ebpf_low_memory_test(size_t stack_depth = EBPF_ALLOCATION_STACK_CAPTURE_FRAME_COUNT_FOR_HASH)
: _stack_depth(stack_depth)
{
@ -52,8 +77,14 @@ _ebpf_low_memory_test::fail_stack_allocation()
bool
_ebpf_low_memory_test::is_new_stack()
{
// Prevent infinite recursion during allocation.
ebpf_low_memory_test_recursion_guard recursion_guard;
if (recursion_guard.is_recursing()) {
return false;
}
std::vector<uintptr_t> stack(EBPF_ALLOCATION_STACK_CAPTURE_FRAME_COUNT);
std::vector<uintptr_t> canonical_stack(_stack_depth);
DWORD hash;
// Capture EBPF_ALLOCATION_STACK_CAPTURE_FRAME_COUNT_FOR_HASH frames of the current stack trace.
if (CaptureStackBackTrace(

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

@ -349,6 +349,10 @@ __drv_allocatesMem(Mem) _Must_inspect_result_ _Ret_maybenull_
return nullptr;
}
if (_ebpf_low_memory_test_ptr && _ebpf_low_memory_test_ptr->fail_stack_allocation()) {
return nullptr;
}
void* memory = _aligned_malloc(size, EBPF_CACHE_LINE_SIZE);
if (memory) {
memset(memory, 0, size);
@ -380,7 +384,7 @@ typedef struct _ebpf_ring_descriptor ebpf_ring_descriptor_t;
ebpf_memory_descriptor_t*
ebpf_map_memory(size_t length)
{
ebpf_memory_descriptor_t* descriptor = (ebpf_memory_descriptor_t*)malloc(sizeof(ebpf_memory_descriptor_t));
ebpf_memory_descriptor_t* descriptor = (ebpf_memory_descriptor_t*)ebpf_allocate(sizeof(ebpf_memory_descriptor_t));
if (!descriptor) {
return nullptr;
}

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

@ -136,7 +136,7 @@ ExAllocatePoolUninitialized(_In_ POOL_TYPE pool_type, _In_ size_t number_of_byte
{
UNREFERENCED_PARAMETER(pool_type);
UNREFERENCED_PARAMETER(tag);
return malloc(number_of_bytes);
return ebpf_allocate(number_of_bytes);
}
void
@ -174,7 +174,7 @@ IoAllocateMdl(
UNREFERENCED_PARAMETER(charge_quota);
UNREFERENCED_PARAMETER(irp);
mdl = reinterpret_cast<MDL*>(malloc(sizeof(MDL)));
mdl = reinterpret_cast<MDL*>(ebpf_allocate(sizeof(MDL)));
if (mdl == NULL) {
return mdl;
}
@ -200,7 +200,7 @@ io_work_item_wrapper(_Inout_ PTP_CALLBACK_INSTANCE instance, _Inout_opt_ PVOID c
PIO_WORKITEM
IoAllocateWorkItem(_In_ DEVICE_OBJECT* device_object)
{
auto work_item = reinterpret_cast<IO_WORKITEM*>(malloc(sizeof(IO_WORKITEM)));
auto work_item = reinterpret_cast<IO_WORKITEM*>(ebpf_allocate(sizeof(IO_WORKITEM)));
if (!work_item) {
return nullptr;
}