Skip to content

Commit

Permalink
program information serialization (microsoft#302)
Browse files Browse the repository at this point in the history
* program information serialization.

Co-authored-by: Dave Thaler <dthaler@microsoft.com>
  • Loading branch information
shankarseal and dthaler authored Jun 28, 2021
1 parent a0801d4 commit a93f4ba
Show file tree
Hide file tree
Showing 21 changed files with 923 additions and 342 deletions.
19 changes: 17 additions & 2 deletions include/ebpf_program_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ typedef unsigned long long uint64_t;
#endif
#include "../external/ebpf-verifier/src/ebpf_base.h"

#define EBPF_MAX_PROGRAM_DESCRIPTOR_NAME_LENGTH 256
#define EBPF_MAX_HELPER_FUNCTION_NAME_LENGTH 256

typedef struct _ebpf_program_type_descriptor
{
MIDL([string])
const char* name;
ebpf_context_descriptor_t* context_descriptor;
GUID platform_specific_data;
GUID program_type;
char is_privileged;
} ebpf_program_type_descriptor_t;

Expand All @@ -39,4 +42,16 @@ typedef struct _ebpf_program_information
ebpf_program_type_descriptor_t program_type_descriptor;
uint32_t count_of_helpers;
MIDL([size_is(count_of_helpers)]) ebpf_helper_function_prototype_t* helper_prototype;
} ebpf_program_information_t;
} ebpf_program_information_t;

typedef struct _ebpf_helper_function_addresses
{
uint32_t helper_function_count;
MIDL([size_is(helper_function_count)]) uint64_t* helper_function_address;
} ebpf_helper_function_addresses_t;

typedef struct _ebpf_program_data
{
ebpf_program_information_t* program_information;
ebpf_helper_function_addresses_t* helper_function_addresses;
} ebpf_program_data_t;
7 changes: 4 additions & 3 deletions libs/api/api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ ebpf_get_program_byte_code(
_Out_ int* map_descriptors_count,
_Outptr_result_maybenull_ const char** error_message);

uint32_t
get_program_information_data(ebpf_program_type_t program_type, ebpf_extension_data_t** program_information_data);
ebpf_result_t
get_program_information_data(
ebpf_program_type_t program_type, _Outptr_ ebpf_program_information_t** program_information);

void
clean_up_ebpf_program(_In_ _Post_invalid_ ebpf_program_t* program);
Expand All @@ -61,4 +62,4 @@ void
clean_up_ebpf_programs(_Inout_ std::vector<ebpf_program_t*>& programs);

void
clean_up_ebpf_maps(_Inout_ std::vector<ebpf_map_t*>& maps);
clean_up_ebpf_maps(_Inout_ std::vector<ebpf_map_t*>& maps);
102 changes: 65 additions & 37 deletions libs/api_common/windows_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
#include <stdexcept>
#include <vector>
#include <Windows.h>
#include "api_common.hpp"
#include "device_helper.hpp"
#include "ebpf_bind_program_data.h"
#include "ebpf_platform.h"
#include "ebpf_program_types.h"
#include "ebpf_protocol.h"
#include "ebpf_result.h"
#include "ebpf_serialize.h"
#include "ebpf_xdp_program_data.h"
#include "platform.h"
#include "platform.hpp"
Expand All @@ -24,44 +26,61 @@ struct guid_compare
}
};

static thread_local std::map<GUID, ebpf_helper::ebpf_memory_ptr, guid_compare> _program_information_cache;
struct _ebpf_program_information_deleter
{
void
operator()(_In_ _Post_invalid_ ebpf_program_information_t* program_info)
{
ebpf_program_information_free(program_info);
}
};

typedef std::unique_ptr<ebpf_program_information_t, _ebpf_program_information_deleter> ebpf_program_information_ptr_t;
static thread_local std::map<GUID, ebpf_program_information_ptr_t, guid_compare> _program_information_cache;

static thread_local std::map<GUID, ebpf_helper::ebpf_memory_ptr, guid_compare> _static_program_information_cache;

void
clear_program_information_cache()
{
_program_information_cache.clear();
}

uint32_t
get_program_information_data(ebpf_program_type_t program_type, ebpf_extension_data_t** program_information_data)
ebpf_result_t
get_program_information_data(
ebpf_program_type_t program_type, _Outptr_ ebpf_program_information_t** program_information)
{
ebpf_protocol_buffer_t reply_buffer(1024);
size_t required_buffer_length;
ebpf_operation_get_program_information_request_t request{
sizeof(request), ebpf_operation_id_t::EBPF_OPERATION_GET_PROGRAM_INFORMATION, program_type};

*program_information = nullptr;

auto reply = reinterpret_cast<ebpf_operation_get_program_information_reply_t*>(reply_buffer.data());
uint32_t retval = invoke_ioctl(request, reply_buffer);
if (retval != ERROR_SUCCESS) {
return retval;
ebpf_result_t result = windows_error_to_ebpf_result(invoke_ioctl(request, reply_buffer));
if ((result != EBPF_SUCCESS) && (result != EBPF_INSUFFICIENT_BUFFER))
goto Exit;

if (result == EBPF_INSUFFICIENT_BUFFER) {
required_buffer_length = reply->header.length;
reply_buffer.resize(required_buffer_length);
reply = reinterpret_cast<ebpf_operation_get_program_information_reply_t*>(reply_buffer.data());
result = windows_error_to_ebpf_result(invoke_ioctl(request, reply_buffer));
if (result != EBPF_SUCCESS)
goto Exit;
}

if (reply->header.id != ebpf_operation_id_t::EBPF_OPERATION_GET_PROGRAM_INFORMATION) {
return ERROR_INVALID_PARAMETER;
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}

size_t allocation_size =
reply->header.length - EBPF_OFFSET_OF(ebpf_operation_get_program_information_reply_t, version);

*program_information_data = (ebpf_extension_data_t*)malloc(allocation_size);
if (!*program_information_data)
return ERROR_OUTOFMEMORY;
// Deserialize the reply data into program information.
result = ebpf_deserialize_program_information(reply->size, reply->data, program_information);

memcpy(
*program_information_data,
reply_buffer.data() + EBPF_OFFSET_OF(ebpf_operation_get_program_information_reply_t, version),
allocation_size);

return retval;
Exit:
return result;
}

ebpf_result_t
Expand All @@ -72,41 +91,50 @@ get_program_type_info(const ebpf_program_information_t** info)
ebpf_program_information_t* program_information;
const uint8_t* encoded_data = nullptr;
size_t encoded_data_size = 0;
bool fall_back = false;

// See if we already have the program information cached.
auto it = _program_information_cache.find(*program_type);
if (it == _program_information_cache.end()) {
// Try to query the information from the execution context.
ebpf_extension_data_t* program_information_data;
uint32_t error = get_program_information_data(*program_type, &program_information_data);
if (error == ERROR_SUCCESS) {
encoded_data = program_information_data->data;
encoded_data_size = program_information_data->size;
result = get_program_information_data(*program_type, &program_information);
if (result != EBPF_SUCCESS) {
fall_back = true;
} else {
// Fall back to using static data so that verification can be tried
// (e.g., from a netsh command) even if the execution context isn't running.
// TODO: remove this in the future.
_program_information_cache[*program_type] = ebpf_program_information_ptr_t(program_information);
}
}

if (fall_back) {
// Fall back to using static data so that verification can be tried
// (e.g., from a netsh command) even if the execution context isn't running.
// TODO: remove this in the future.
auto iter = _static_program_information_cache.find(*program_type);
if (iter == _static_program_information_cache.end()) {
if (memcmp(program_type, &EBPF_PROGRAM_TYPE_XDP, sizeof(*program_type)) == 0) {
encoded_data = _ebpf_encoded_xdp_program_information_data;
encoded_data_size = sizeof(_ebpf_encoded_xdp_program_information_data);
} else if (memcmp(program_type, &EBPF_PROGRAM_TYPE_BIND, sizeof(*program_type)) == 0) {
encoded_data = _ebpf_encoded_bind_program_information_data;
encoded_data_size = sizeof(_ebpf_encoded_bind_program_information_data);
}
}
if (encoded_data == nullptr) {
return EBPF_INVALID_ARGUMENT;
}
ebpf_assert(encoded_data != nullptr);

result = ebpf_program_information_decode(&program_information, encoded_data, (unsigned long)encoded_data_size);
if (result != EBPF_SUCCESS) {
return result;
}
result =
ebpf_program_information_decode(&program_information, encoded_data, (unsigned long)encoded_data_size);
if (result != EBPF_SUCCESS) {
return result;
}

_program_information_cache[*program_type] = ebpf_helper::ebpf_memory_ptr(program_information);
_static_program_information_cache[*program_type] = ebpf_helper::ebpf_memory_ptr(program_information);
}
}

*info = (const ebpf_program_information_t*)_program_information_cache[*program_type].get();
if (!fall_back) {
*info = (const ebpf_program_information_t*)_program_information_cache[*program_type].get();
} else {
*info = (const ebpf_program_information_t*)_static_program_information_cache[*program_type].get();
}

return EBPF_SUCCESS;
}
Expand Down
3 changes: 2 additions & 1 deletion libs/ebpfnetsh/ebpfnetsh.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LinkIncremental>false</LinkIncremental>
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
Expand Down Expand Up @@ -135,6 +135,7 @@
<AdditionalIncludeDirectories>$(SolutionDir)include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpplatest</LanguageStandard>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>
Expand Down
Loading

0 comments on commit a93f4ba

Please sign in to comment.