Move program load to ebpfsvc (#245)
* remove duplicate windows_helpers.cpp, refactor * remove commented code * move program load to service * cleanup commented code * remove commented code * cr comments * make device handle init optional * cr comments * change return type of some functions * fix * cr comments * cr comments, cover more error conditions in windows_error_to_ebpf_result * cr comments Co-authored-by: Dave Thaler <dthaler@microsoft.com> Co-authored-by: Alan Jowett <alanjo@microsoft.com>
This commit is contained in:
Родитель
7e033f0200
Коммит
cf2ef87325
|
@ -32,6 +32,7 @@ This will build the following binaries:
|
|||
loading eBPF programs.
|
||||
* ebpfnetsh.dll: A plugin for the Windows netsh.exe command line tool that provides eBPF command line
|
||||
utility functionality.
|
||||
* ebpfsvc.exe: A user-mode service that verifies and loads an eBPF program in the execution context.
|
||||
* end_to_end.exe: A collection of tests using the Catch framework. These tests are also run as part
|
||||
of the Github CI/CD so should always pass.
|
||||
|
||||
|
@ -60,14 +61,17 @@ On the defender machine, do the following:
|
|||
3. Install Debug VS 2019 VC redist from TBD (or switch everything to Multi-threaded Debug (/MTd) and rebuild)
|
||||
4. Copy ebpfcore.sys to %windir%\system32\drivers
|
||||
5. Copy netebpfext.sys to %windir%\system32\drivers
|
||||
6. Copy ebpfapi.dll and ebpfnetsh.dll to %windir%\system32
|
||||
7. Do `sc create EbpfCore type=kernel start=boot binpath=%windir%\system32\drivers\ebpfcore.sys`
|
||||
8. Do `sc start EbpfCore`
|
||||
9. Do `sc create NetEbpfExt type=kernel start=boot binpath=%windir%\system32\drivers\netebpfext.sys`
|
||||
10. Do `sc start NetEbpfExt`
|
||||
11. Do `netsh add helper %windir%\system32\ebpfnetsh.dll`
|
||||
12. Install [clang](https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/LLVM-11.0.0-win64.exe)
|
||||
13. Copy droppacket.c and ebpf.h to a folder (such as c:\test)
|
||||
6. Copy ebpfsvc.exe to %windir%\system32
|
||||
7. Copy ebpfapi.dll and ebpfnetsh.dll to %windir%\system32
|
||||
8. Do `sc create EbpfCore type=kernel start=boot binpath=%windir%\system32\drivers\ebpfcore.sys`
|
||||
9. Do `sc start EbpfCore`
|
||||
10. Do `sc create NetEbpfExt type=kernel start=boot binpath=%windir%\system32\drivers\netebpfext.sys`
|
||||
11. Do `sc start NetEbpfExt`
|
||||
12. Do `sc create ebpfsvc start= auto binpath=%windir%\system32\ebpfsvc.exe type=own`
|
||||
13. Do `sc start ebpfsvc`
|
||||
14. Do `netsh add helper %windir%\system32\ebpfnetsh.dll`
|
||||
15. Install [clang](https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/LLVM-11.0.0-win64.exe)
|
||||
16. Copy droppacket.c and ebpf.h to a folder (such as c:\test)
|
||||
|
||||
On the attacker machine, do the following:
|
||||
1. Copy DnsFlood.exe to attacker machine
|
||||
|
|
|
@ -46,6 +46,7 @@ EndProject
|
|||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EbpfApi", "ebpfapi\ebpfapi.vcxproj", "{75FE223A-3E45-4B0E-A2E8-04285E52E440}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{231EE32B-EBA4-4FE5-A55B-DB18F539D403} = {231EE32B-EBA4-4FE5-A55B-DB18F539D403}
|
||||
{1423245D-0249-40FC-A077-FF7780ACFE3F} = {1423245D-0249-40FC-A077-FF7780ACFE3F}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ebpfnetsh", "tools\netsh\ebpfnetsh.vcxproj", "{74803F80-A8BD-4A03-862B-FA96648A9BF6}"
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\api;$(SolutionDir)rpc_interface;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
|
@ -96,7 +96,7 @@
|
|||
<PreprocessorDefinitions>NDEBUG;EBPFAPI_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\api;$(SolutionDir)rpc_interface;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
|
@ -120,6 +120,7 @@
|
|||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="platform.cpp" />
|
||||
<ClCompile Include="rpc_client.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Source.def" />
|
||||
|
@ -137,9 +138,6 @@
|
|||
<ProjectReference Include="..\libs\platform\user\platform_user.vcxproj">
|
||||
<Project>{c26cb6a9-158c-4a9e-a243-755ddd98e5fe}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\libs\service\service.vcxproj">
|
||||
<Project>{af85c549-57cc-40a5-bdfc-dcf1998de80f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\libs\ubpf\user\ubpf_user.vcxproj">
|
||||
<Project>{245f0ec7-1ebc-4d68-8b1f-f758ea9196ae}</Project>
|
||||
</ProjectReference>
|
||||
|
|
|
@ -33,6 +33,9 @@
|
|||
<ClCompile Include="platform.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="rpc_client.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Source.def">
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include "ebpf_api.h"
|
||||
#include "ebpf_windows.h"
|
||||
#include "rpc_interface_c.c"
|
||||
|
||||
#pragma comment(lib, "Rpcrt4.lib")
|
||||
|
||||
static RPC_WSTR _string_binding = nullptr;
|
||||
static const WCHAR* _protocol_sequence = L"ncalrpc";
|
||||
static bool _binding_initialized = false;
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_rpc_verify_program(ebpf_program_verify_info* info, const char** logs, uint32_t* logs_size) noexcept
|
||||
{
|
||||
ebpf_result_t result;
|
||||
|
||||
RpcTryExcept { result = ebpf_client_verify_program(info, logs_size, const_cast<char**>(logs)); }
|
||||
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
|
||||
{
|
||||
// TODO: (Issue# 247) Add tracing for the RpcExceptionCode() that is returned.
|
||||
result = EBPF_RPC_EXCEPTION;
|
||||
}
|
||||
RpcEndExcept
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_rpc_load_program(ebpf_program_load_info* info, const char** logs, uint32_t* logs_size) noexcept
|
||||
{
|
||||
ebpf_result_t result;
|
||||
|
||||
RpcTryExcept { result = ebpf_client_verify_and_load_program(info, logs_size, const_cast<char**>(logs)); }
|
||||
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
|
||||
{
|
||||
// TODO: (Issue# 247) Add tracing for the RpcExceptionCode() that is returned.
|
||||
result = EBPF_RPC_EXCEPTION;
|
||||
}
|
||||
RpcEndExcept
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RPC_STATUS
|
||||
initialize_rpc_binding()
|
||||
{
|
||||
RPC_STATUS status =
|
||||
RpcStringBindingCompose(nullptr, (RPC_WSTR)_protocol_sequence, nullptr, nullptr, nullptr, &_string_binding);
|
||||
|
||||
if (status != RPC_S_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = RpcBindingFromStringBinding(_string_binding, &ebpf_service_interface_handle);
|
||||
if (status == RPC_S_OK) {
|
||||
_binding_initialized = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
RPC_STATUS
|
||||
clean_up_rpc_binding()
|
||||
{
|
||||
RPC_STATUS status = RpcStringFree(&_string_binding);
|
||||
if (status != RPC_S_OK) {
|
||||
printf("RpcStringFree failed with error %d\n", status);
|
||||
}
|
||||
|
||||
if (_binding_initialized) {
|
||||
status = RpcBindingFree(&ebpf_service_interface_handle);
|
||||
if (status != RPC_S_OK) {
|
||||
printf("RpcBindingFree failed with error %d\n", status);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
|
@ -134,7 +134,7 @@
|
|||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\api;$(SolutionDir)libs\platform;$(SolutionDir)libs\service;$(SolutionDir)include;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform\user;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\api_common;$(SolutionDir)libs\execution_context;$(SolutionDir)libs\api;$(SolutionDir)libs\platform;$(SolutionDir)libs\service;$(SolutionDir)include;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform\user;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
|
|
@ -5,29 +5,36 @@
|
|||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include "api_internal.h"
|
||||
#include "api_service.h"
|
||||
#include "ebpf_windows.h"
|
||||
#include "rpc_interface_h.h"
|
||||
#include "svc_common.h"
|
||||
#include "Verifier.h"
|
||||
|
||||
// Critical section to serialize RPC calls.
|
||||
// Currently ebpfsvc uses a global context to track verification
|
||||
// and JIT compilation, hence all RPC calls should be serialized.
|
||||
static std::mutex _mutex;
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_server_verify_and_jit_program(
|
||||
ebpf_server_verify_and_load_program(
|
||||
/* [ref][in] */ ebpf_program_load_info* info,
|
||||
/* [ref][out] */ uint32_t* logs_size,
|
||||
/* [ref][size_is][size_is][out] */ char** logs)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(info);
|
||||
UNREFERENCED_PARAMETER(logs_size);
|
||||
UNREFERENCED_PARAMETER(logs);
|
||||
ebpf_result_t result;
|
||||
|
||||
return EBPF_FAILED;
|
||||
if (info->byte_code_size == 0) {
|
||||
return EBPF_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
result = ebpf_verify_and_load_program(
|
||||
&info->program_type,
|
||||
info->program_handle,
|
||||
info->execution_context,
|
||||
info->execution_type,
|
||||
info->map_count,
|
||||
info->handle_map,
|
||||
info->byte_code_size,
|
||||
info->byte_code,
|
||||
const_cast<const char**>(logs),
|
||||
logs_size);
|
||||
|
||||
ebpf_clear_thread_local_storage();
|
||||
return result;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
|
@ -36,17 +43,17 @@ ebpf_server_verify_program(
|
|||
/* [out] */ uint32_t* logs_size,
|
||||
/* [ref][size_is][size_is][out] */ char** logs)
|
||||
{
|
||||
ebpf_result_t result;
|
||||
|
||||
if (info->byte_code_size == 0) {
|
||||
return EBPF_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(_mutex);
|
||||
|
||||
// MIDL generates warnings if any [out] param uses 'const',
|
||||
// since RPC marshaling will copy the data anyway. So we
|
||||
// can safely cast the 'logs' param below.
|
||||
|
||||
return ebpf_verify_program(
|
||||
result = ebpf_verify_program(
|
||||
reinterpret_cast<const GUID*>(&info->program_type),
|
||||
info->execution_context,
|
||||
info->map_descriptors_count,
|
||||
|
@ -55,4 +62,7 @@ ebpf_server_verify_program(
|
|||
info->byte_code,
|
||||
const_cast<const char**>(logs),
|
||||
logs_size);
|
||||
|
||||
ebpf_clear_thread_local_storage();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -7,38 +7,46 @@
|
|||
|
||||
#pragma comment(lib, "Rpcrt4.lib")
|
||||
|
||||
#define RPC_SERVER_ENDPOINT L"\\pipe\\ebpf_service"
|
||||
#define ANNOTATION L"ebpfsvc rpc server"
|
||||
#define EBPF_SERVICE_INTERFACE_HANDLE ebpf_server_ebpf_service_interface_v1_0_s_ifspec
|
||||
|
||||
static const WCHAR* _protocol_sequence = L"ncalrpc";
|
||||
static bool _rpc_server_initialized = false;
|
||||
|
||||
DWORD
|
||||
initialize_rpc_server()
|
||||
{
|
||||
RPC_STATUS status;
|
||||
const WCHAR* protocol_sequence = L"ncacn_np";
|
||||
unsigned char* security = nullptr;
|
||||
const WCHAR* endpoint = RPC_SERVER_ENDPOINT;
|
||||
unsigned int minimum_calls = 1;
|
||||
unsigned int dont_wait = true;
|
||||
bool registered = false;
|
||||
RPC_BINDING_VECTOR* binding_vector = nullptr;
|
||||
|
||||
status = RpcServerUseProtseqEp(
|
||||
(RPC_WSTR)protocol_sequence, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (RPC_WSTR)endpoint, security);
|
||||
status = RpcServerUseProtseq((RPC_WSTR)_protocol_sequence, RPC_C_PROTSEQ_MAX_REQS_DEFAULT, nullptr);
|
||||
if (status != RPC_S_OK) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
status = RpcServerRegisterIf(ebpf_server_ebpf_service_interface_v1_0_s_ifspec, nullptr, nullptr);
|
||||
status = RpcServerRegisterIfEx(
|
||||
EBPF_SERVICE_INTERFACE_HANDLE, nullptr, nullptr, RPC_IF_AUTOLISTEN, RPC_C_LISTEN_MAX_CALLS_DEFAULT, nullptr);
|
||||
if (status != RPC_S_OK) {
|
||||
goto Exit;
|
||||
}
|
||||
registered = true;
|
||||
|
||||
status = RpcServerListen(minimum_calls, RPC_C_LISTEN_MAX_CALLS_DEFAULT, dont_wait);
|
||||
status = RpcServerInqBindings(&binding_vector);
|
||||
if (status != RPC_S_OK) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
status = RpcEpRegister(EBPF_SERVICE_INTERFACE_HANDLE, binding_vector, NULL, (RPC_WSTR)ANNOTATION);
|
||||
|
||||
if (status == RPC_S_OK) {
|
||||
_rpc_server_initialized = true;
|
||||
}
|
||||
|
||||
Exit:
|
||||
if (binding_vector != nullptr) {
|
||||
RpcBindingVectorFree(&binding_vector);
|
||||
}
|
||||
if (status != RPC_S_OK) {
|
||||
if (registered) {
|
||||
RpcServerUnregisterIf(nullptr, nullptr, true);
|
||||
|
@ -50,22 +58,32 @@ Exit:
|
|||
void
|
||||
shutdown_rpc_server()
|
||||
{
|
||||
RPC_STATUS status;
|
||||
RPC_BINDING_VECTOR* binding_vector = nullptr;
|
||||
|
||||
if (!_rpc_server_initialized) {
|
||||
return;
|
||||
}
|
||||
RPC_STATUS status;
|
||||
|
||||
status = RpcMgmtStopServerListening(nullptr);
|
||||
status = RpcServerInqBindings(&binding_vector);
|
||||
if (status != RPC_S_OK) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
status = RpcEpUnregister(EBPF_SERVICE_INTERFACE_HANDLE, binding_vector, nullptr);
|
||||
if (status != RPC_S_OK) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
status = RpcServerUnregisterIf(EBPF_SERVICE_INTERFACE_HANDLE, nullptr, true);
|
||||
if (status != RPC_S_OK) {
|
||||
// TODO: Add a trace that something happened.
|
||||
return;
|
||||
}
|
||||
|
||||
status = RpcServerUnregisterIf(nullptr, nullptr, true);
|
||||
if (status != RPC_S_OK) {
|
||||
// TODO: Add a trace that something happened.
|
||||
return;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
if (binding_vector != nullptr) {
|
||||
RpcBindingVectorFree(&binding_vector);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "api_service.h"
|
||||
#include "rpc_util.h"
|
||||
#include "svc_common.h"
|
||||
|
||||
|
@ -198,7 +199,13 @@ Initialize()
|
|||
{
|
||||
DWORD status;
|
||||
status = initialize_rpc_server();
|
||||
if (status != ERROR_SUCCESS) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
status = ebpf_service_initialize();
|
||||
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -206,6 +213,7 @@ void
|
|||
Cleanup()
|
||||
{
|
||||
shutdown_rpc_server();
|
||||
ebpf_service_cleanup();
|
||||
if (ebpf_service_stop_event_handle) {
|
||||
CloseHandle(ebpf_service_stop_event_handle);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ebpf_execution_type.h"
|
||||
#include "ebpf_result.h"
|
||||
#include "ebpf_windows.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -33,12 +34,6 @@ extern "C"
|
|||
const ebpf_handle_t ebpf_handle_invalid = (ebpf_handle_t)-1;
|
||||
typedef struct _tlv_type_length_value tlv_type_length_value_t;
|
||||
|
||||
typedef enum _ebpf_execution_type
|
||||
{
|
||||
EBPF_EXECUTION_JIT,
|
||||
EBPF_EXECUTION_INTERPRET
|
||||
} ebpf_execution_type_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the eBPF user mode library.
|
||||
*/
|
||||
|
@ -63,7 +58,7 @@ extern "C"
|
|||
* @param[out] map_handles Array of map handles to be filled in.
|
||||
* @param[out] error_message Error message describing what failed.
|
||||
*/
|
||||
uint32_t
|
||||
ebpf_result_t
|
||||
ebpf_api_load_program(
|
||||
const char* file,
|
||||
const char* section_name,
|
||||
|
@ -148,7 +143,7 @@ extern "C"
|
|||
* @param[out] value_size Size of values in the eBPF map.
|
||||
* @param[out] max_entries Maximum number of entries in the map.
|
||||
*/
|
||||
uint32_t
|
||||
ebpf_result_t
|
||||
ebpf_api_map_query_definition(
|
||||
ebpf_handle_t handle,
|
||||
uint32_t* size,
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum _ebpf_execution_type
|
||||
{
|
||||
EBPF_EXECUTION_JIT,
|
||||
EBPF_EXECUTION_INTERPRET
|
||||
} ebpf_execution_type_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -18,8 +18,11 @@ extern "C"
|
|||
// Program verification failed.
|
||||
EBPF_VALIDATION_FAILED,
|
||||
|
||||
// JIT compilation failed.
|
||||
EBPF_JIT_COMPILATION_FAILED,
|
||||
|
||||
// Program load failed.
|
||||
EBPF_LOAD_FAILED,
|
||||
EBPF_PROGRAM_LOAD_FAILED,
|
||||
|
||||
// Invalid FD provided.
|
||||
EBPF_INVALID_FD,
|
||||
|
@ -48,6 +51,15 @@ extern "C"
|
|||
// Low memory.
|
||||
EBPF_NO_MEMORY,
|
||||
|
||||
// The program is too large.
|
||||
EBPF_PROGRAM_TOO_LARGE,
|
||||
|
||||
// RPC exception.
|
||||
EBPF_RPC_EXCEPTION,
|
||||
|
||||
// Handle is already initialized.
|
||||
EBPF_ALREADY_INITIALIZED,
|
||||
|
||||
// Generic failure code for all other errors.
|
||||
EBPF_FAILED,
|
||||
|
||||
|
|
|
@ -51,6 +51,12 @@ load_byte_code(
|
|||
|
||||
// copy out the bytecode for the jitter
|
||||
size_t ebpf_bytes = raw_prog.prog.size() * sizeof(ebpf_inst);
|
||||
|
||||
// Check if the raw program can fit in the supplied buffer.
|
||||
if (ebpf_bytes > *byte_code_size) {
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (ebpf_inst inst : raw_prog.prog) {
|
||||
char* buf = (char*)&inst;
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\api;$(SolutionDir)rpc_interface;$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
|
@ -152,7 +152,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)rpc_interface;$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
|
@ -176,6 +176,7 @@
|
|||
<ClInclude Include="api_internal.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="platform.h" />
|
||||
<ClInclude Include="rpc_client.h" />
|
||||
<ClInclude Include="tlv.h" />
|
||||
<ClInclude Include="Verifier.h" />
|
||||
<ClInclude Include="windows_platform.hpp" />
|
||||
|
|
|
@ -45,5 +45,8 @@
|
|||
<ClInclude Include="api_internal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rpc_client.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -2,55 +2,44 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "pch.h"
|
||||
#include "ebpf_api.h"
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include "api_common.hpp"
|
||||
#include "device_helper.hpp"
|
||||
#include "ebpf_api.h"
|
||||
#include "ebpf_protocol.h"
|
||||
#include "ebpf_platform.h"
|
||||
#include "map_descriptors.hpp"
|
||||
#include "platform.h"
|
||||
#include "rpc_client.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "ubpf.h"
|
||||
}
|
||||
#include "Verifier.h"
|
||||
#include "verifier_service.h"
|
||||
#include "windows_helpers.hpp"
|
||||
|
||||
#define MAX_CODE_SIZE (32 * 1024) // 32 KB
|
||||
|
||||
uint32_t
|
||||
ebpf_api_initiate()
|
||||
{
|
||||
if (device_handle != INVALID_HANDLE_VALUE) {
|
||||
return ERROR_ALREADY_INITIALIZED;
|
||||
uint32_t result;
|
||||
|
||||
// This is best effort. If device handle does not initialize,
|
||||
// it will be re-attempted before an IOCTL call is made.
|
||||
initialize_device_handle();
|
||||
|
||||
result = initialize_rpc_binding();
|
||||
|
||||
if (result != ERROR_SUCCESS) {
|
||||
clean_up_device_handle();
|
||||
clean_up_rpc_binding();
|
||||
}
|
||||
|
||||
device_handle = Platform::CreateFile(
|
||||
EBPF_DEVICE_WIN32_NAME,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
|
||||
if (device_handle == INVALID_HANDLE_VALUE) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
return 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
ebpf_api_terminate()
|
||||
{
|
||||
if (device_handle != INVALID_HANDLE_VALUE) {
|
||||
Platform::CloseHandle(device_handle);
|
||||
device_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
clean_up_device_handle();
|
||||
clean_up_rpc_binding();
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -64,7 +53,7 @@ create_map_function(
|
|||
|
||||
_ebpf_operation_create_map_reply reply{};
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply);
|
||||
uint32_t retval = invoke_ioctl(request, reply);
|
||||
if (retval != ERROR_SUCCESS) {
|
||||
throw std::runtime_error(std::string("Error ") + std::to_string(retval) + " trying to create map");
|
||||
}
|
||||
|
@ -73,165 +62,10 @@ create_map_function(
|
|||
throw std::runtime_error(std::string("reply.header.id != ebpf_operation_id_t::EBPF_OPERATION_CREATE_MAP"));
|
||||
}
|
||||
|
||||
return cache_map_handle(reply.handle, type, key_size, value_size);
|
||||
return cache_map_handle(reply.handle, type, key_size, value_size, max_entries);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
resolve_maps_in_byte_code(ebpf_handle_t program_handle, ebpf_code_buffer_t& byte_code)
|
||||
{
|
||||
// Maintain two maps.
|
||||
// First map is instruction offset -> map handle.
|
||||
// Second map is map handle -> map address.
|
||||
std::map<size_t, uint64_t> instruction_offsets_to_map_handles;
|
||||
std::map<uint64_t, uint64_t> map_handles_to_map_addresses;
|
||||
|
||||
ebpf_inst* instructions = reinterpret_cast<ebpf_inst*>(byte_code.data());
|
||||
ebpf_inst* instruction_end = reinterpret_cast<ebpf_inst*>(byte_code.data() + byte_code.size());
|
||||
for (size_t index = 0; index < byte_code.size() / sizeof(ebpf_inst); index++) {
|
||||
ebpf_inst& first_instruction = instructions[index];
|
||||
ebpf_inst& second_instruction = instructions[index + 1];
|
||||
if (first_instruction.opcode != INST_OP_LDDW_IMM) {
|
||||
continue;
|
||||
}
|
||||
if (&instructions[index + 1] >= instruction_end) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
index++;
|
||||
|
||||
// Check for LD_MAP flag
|
||||
if (first_instruction.src != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t imm =
|
||||
static_cast<uint64_t>(first_instruction.imm) | (static_cast<uint64_t>(second_instruction.imm) << 32);
|
||||
|
||||
// Collect set of instructions to patch with the value to replace.
|
||||
instruction_offsets_to_map_handles[index - 1] = imm;
|
||||
|
||||
// Collect set of map handles.
|
||||
map_handles_to_map_addresses[imm] = 0;
|
||||
}
|
||||
|
||||
if (instruction_offsets_to_map_handles.size() == 0) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
ebpf_protocol_buffer_t request_buffer(
|
||||
offsetof(ebpf_operation_resolve_map_request_t, map_handle) +
|
||||
sizeof(uint64_t) * map_handles_to_map_addresses.size());
|
||||
|
||||
ebpf_protocol_buffer_t reply_buffer(
|
||||
offsetof(ebpf_operation_resolve_map_reply_t, address) + sizeof(uint64_t) * map_handles_to_map_addresses.size());
|
||||
|
||||
auto request = reinterpret_cast<ebpf_operation_resolve_map_request_t*>(request_buffer.data());
|
||||
auto reply = reinterpret_cast<ebpf_operation_resolve_map_reply_t*>(reply_buffer.data());
|
||||
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_RESOLVE_MAP;
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->program_handle = reinterpret_cast<uint64_t>(program_handle);
|
||||
|
||||
size_t index = 0;
|
||||
for (auto& [map_handle, map_address] : map_handles_to_map_addresses) {
|
||||
|
||||
if (map_handle > get_map_descriptor_size()) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
request->map_handle[index++] = get_map_handle_at_index(map_handle - 1);
|
||||
}
|
||||
|
||||
uint32_t result = invoke_ioctl(device_handle, request_buffer, reply_buffer);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
for (auto& [map_handle, map_address] : map_handles_to_map_addresses) {
|
||||
map_address = reply->address[index++];
|
||||
}
|
||||
|
||||
for (auto& [instruction_offset, map_handle] : instruction_offsets_to_map_handles) {
|
||||
ebpf_inst& first_instruction = instructions[instruction_offset];
|
||||
ebpf_inst& second_instruction = instructions[instruction_offset + 1];
|
||||
|
||||
// Clear LD_MAP flag
|
||||
first_instruction.src = 0;
|
||||
|
||||
// Replace handle with address
|
||||
uint64_t new_imm = map_handles_to_map_addresses[map_handle];
|
||||
first_instruction.imm = static_cast<uint32_t>(new_imm);
|
||||
second_instruction.imm = static_cast<uint32_t>(new_imm >> 32);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
build_helper_id_to_address_map(
|
||||
ebpf_handle_t program_handle, ebpf_code_buffer_t& byte_code, std::map<uint32_t, uint64_t>& helper_id_to_adddress)
|
||||
{
|
||||
ebpf_inst* instructions = reinterpret_cast<ebpf_inst*>(byte_code.data());
|
||||
for (size_t index = 0; index < byte_code.size() / sizeof(ebpf_inst); index++) {
|
||||
ebpf_inst& instruction = instructions[index];
|
||||
if (instruction.opcode != INST_OP_CALL) {
|
||||
continue;
|
||||
}
|
||||
helper_id_to_adddress[instruction.imm] = 0;
|
||||
}
|
||||
|
||||
if (helper_id_to_adddress.size() == 0)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
ebpf_protocol_buffer_t request_buffer(
|
||||
offsetof(ebpf_operation_resolve_helper_request_t, helper_id) + sizeof(uint32_t) * helper_id_to_adddress.size());
|
||||
|
||||
ebpf_protocol_buffer_t reply_buffer(
|
||||
offsetof(ebpf_operation_resolve_helper_reply_t, address) + sizeof(uint64_t) * helper_id_to_adddress.size());
|
||||
|
||||
auto request = reinterpret_cast<ebpf_operation_resolve_helper_request_t*>(request_buffer.data());
|
||||
auto reply = reinterpret_cast<ebpf_operation_resolve_helper_reply_t*>(reply_buffer.data());
|
||||
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_RESOLVE_HELPER;
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->program_handle = reinterpret_cast<uint64_t>(program_handle);
|
||||
|
||||
size_t index = 0;
|
||||
for (const auto& helper : helper_id_to_adddress) {
|
||||
request->helper_id[index++] = helper.first;
|
||||
}
|
||||
|
||||
uint32_t result = invoke_ioctl(device_handle, request_buffer, reply_buffer);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
for (auto& helper : helper_id_to_adddress) {
|
||||
helper.second = reply->address[index++];
|
||||
}
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
resolve_ec_function(ebpf_ec_function_t function, uint64_t* address)
|
||||
{
|
||||
ebpf_operation_get_ec_function_request_t request = {sizeof(request), EBPF_OPERATION_GET_EC_FUNCTION, function};
|
||||
ebpf_operation_get_ec_function_reply_t reply;
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply);
|
||||
if (retval != ERROR_SUCCESS) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (reply.header.id != ebpf_operation_id_t::EBPF_OPERATION_GET_EC_FUNCTION) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
*address = reply.address;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
static ebpf_result_t
|
||||
_create_program(
|
||||
ebpf_program_type_t program_type,
|
||||
const std::string& file_name,
|
||||
|
@ -258,12 +92,14 @@ _create_program(
|
|||
|
||||
std::copy(section_name.begin(), section_name.end(), request_buffer.begin() + request->section_name_offset);
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request_buffer, reply);
|
||||
if (retval != ERROR_SUCCESS) {
|
||||
return retval;
|
||||
uint32_t error = invoke_ioctl(request_buffer, reply);
|
||||
if (error != ERROR_SUCCESS) {
|
||||
goto Exit;
|
||||
}
|
||||
*program_handle = reinterpret_cast<ebpf_handle_t>(reply.program_handle);
|
||||
return retval;
|
||||
|
||||
Exit:
|
||||
return windows_error_to_ebpf_result(error);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -328,7 +164,7 @@ Done:
|
|||
return result;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ebpf_result_t
|
||||
ebpf_api_load_program(
|
||||
const char* file_name,
|
||||
const char* section_name,
|
||||
|
@ -343,18 +179,18 @@ ebpf_api_load_program(
|
|||
ebpf_code_buffer_t byte_code(MAX_CODE_SIZE);
|
||||
size_t byte_code_size = byte_code.size();
|
||||
ebpf_protocol_buffer_t request_buffer;
|
||||
struct ubpf_vm* vm = nullptr;
|
||||
uint64_t log_function_address;
|
||||
ebpf_operation_load_code_request_t* request = nullptr;
|
||||
uint32_t error_message_size = 0;
|
||||
std::vector<uintptr_t> handles;
|
||||
uint32_t result;
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
ebpf_program_load_info load_info = {0};
|
||||
std::vector<fd_handle_map> handle_map;
|
||||
|
||||
*handle = 0;
|
||||
*error_message = nullptr;
|
||||
|
||||
clear_map_descriptors();
|
||||
|
||||
try {
|
||||
ebpf_verifier_options_t verifier_options{false, false, false, false, false};
|
||||
if (load_byte_code(
|
||||
file_name,
|
||||
|
@ -364,27 +200,52 @@ ebpf_api_load_program(
|
|||
&byte_code_size,
|
||||
&program_type,
|
||||
error_message) != 0) {
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
byte_code.resize(byte_code_size);
|
||||
|
||||
// TODO: (issue #169): Should switch this to more idiomatic C++
|
||||
// Note: This leaks the program handle on some errors.
|
||||
result = _create_program(program_type, file_name, section_name, &program_handle);
|
||||
if (result != ERROR_SUCCESS)
|
||||
goto Done;
|
||||
|
||||
// Verify code.
|
||||
if (verify_byte_code(&program_type, byte_code.data(), byte_code_size, error_message, &error_message_size) != 0) {
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
if (result != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (get_map_descriptor_size() > *count_of_map_handles) {
|
||||
result = ERROR_INSUFFICIENT_BUFFER;
|
||||
result = EBPF_ERROR_INSUFFICIENT_BUFFER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// populate load_info.
|
||||
load_info.file_name = const_cast<char*>(file_name);
|
||||
load_info.section_name = const_cast<char*>(section_name);
|
||||
load_info.program_name = nullptr;
|
||||
load_info.program_type = program_type;
|
||||
load_info.program_handle = program_handle;
|
||||
load_info.execution_type = execution_type;
|
||||
load_info.byte_code = byte_code.data();
|
||||
load_info.byte_code_size = (uint32_t)byte_code_size;
|
||||
load_info.execution_context = execution_context_kernel_mode;
|
||||
load_info.map_count = (uint32_t)get_map_descriptor_size();
|
||||
|
||||
if (load_info.map_count > 0) {
|
||||
auto descriptors = get_all_map_descriptors();
|
||||
for (const auto& descriptor : descriptors) {
|
||||
handle_map.emplace_back(
|
||||
descriptor.ebpf_map_descriptor.original_fd, reinterpret_cast<file_handle_t>(descriptor.handle));
|
||||
}
|
||||
|
||||
load_info.handle_map = handle_map.data();
|
||||
}
|
||||
|
||||
result = ebpf_rpc_load_program(&load_info, error_message, &error_message_size);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// Program is verified and loaded.
|
||||
*count_of_map_handles = 0;
|
||||
handles = get_all_map_handles();
|
||||
for (const auto& map_handle : handles) {
|
||||
|
@ -392,74 +253,18 @@ ebpf_api_load_program(
|
|||
(*count_of_map_handles)++;
|
||||
}
|
||||
|
||||
byte_code.resize(byte_code_size);
|
||||
result = resolve_maps_in_byte_code(program_handle, byte_code);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
result = resolve_ec_function(EBPF_EC_FUNCTION_LOG, &log_function_address);
|
||||
if (result != ERROR_SUCCESS)
|
||||
goto Done;
|
||||
|
||||
if (execution_type == EBPF_EXECUTION_JIT) {
|
||||
std::map<uint32_t, uint64_t> helper_id_to_adddress;
|
||||
result = build_helper_id_to_address_map(program_handle, byte_code, helper_id_to_adddress);
|
||||
if (result != ERROR_SUCCESS)
|
||||
goto Done;
|
||||
|
||||
ebpf_code_buffer_t machine_code(MAX_CODE_SIZE);
|
||||
size_t machine_code_size = machine_code.size();
|
||||
|
||||
// JIT code.
|
||||
vm = ubpf_create();
|
||||
if (vm == nullptr)
|
||||
goto Done;
|
||||
|
||||
for (const auto& helper : helper_id_to_adddress) {
|
||||
if (ubpf_register(vm, helper.first, nullptr, reinterpret_cast<void*>(helper.second)) < 0)
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ubpf_set_error_print(
|
||||
vm, reinterpret_cast<int (*)(FILE * stream, const char* format, ...)>(log_function_address));
|
||||
|
||||
if (ubpf_load(
|
||||
vm, byte_code.data(), static_cast<uint32_t>(byte_code.size()), const_cast<char**>(error_message)) < 0) {
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (ubpf_translate(vm, machine_code.data(), &machine_code_size, const_cast<char**>(error_message))) {
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
machine_code.resize(machine_code_size);
|
||||
byte_code = machine_code;
|
||||
}
|
||||
|
||||
request_buffer.resize(offsetof(ebpf_operation_load_code_request_t, code) + byte_code.size());
|
||||
request = reinterpret_cast<ebpf_operation_load_code_request_t*>(request_buffer.data());
|
||||
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_LOAD_CODE;
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->program_handle = reinterpret_cast<uint64_t>(program_handle);
|
||||
request->code_type = execution_type == EBPF_EXECUTION_JIT ? EBPF_CODE_NATIVE : EBPF_CODE_EBPF;
|
||||
|
||||
std::copy(
|
||||
byte_code.begin(),
|
||||
byte_code.end(),
|
||||
request_buffer.begin() + offsetof(ebpf_operation_load_code_request_t, code));
|
||||
|
||||
result = invoke_ioctl(device_handle, request_buffer);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
goto Done;
|
||||
|
||||
*handle = program_handle;
|
||||
program_handle = INVALID_HANDLE_VALUE;
|
||||
} catch (const std::bad_alloc&) {
|
||||
result = EBPF_NO_MEMORY;
|
||||
goto Done;
|
||||
} catch (...) {
|
||||
result = EBPF_FAILED;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
if (result != ERROR_SUCCESS) {
|
||||
if (result != EBPF_SUCCESS) {
|
||||
handles = get_all_map_handles();
|
||||
for (const auto& map_handle : handles) {
|
||||
ebpf_api_close_handle((ebpf_handle_t)map_handle);
|
||||
|
@ -467,11 +272,9 @@ Done:
|
|||
}
|
||||
clear_map_descriptors();
|
||||
|
||||
if (vm)
|
||||
ubpf_destroy(vm);
|
||||
|
||||
if (program_handle != INVALID_HANDLE_VALUE)
|
||||
if (program_handle != INVALID_HANDLE_VALUE) {
|
||||
ebpf_api_close_handle(program_handle);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -492,7 +295,7 @@ ebpf_api_pin_object(ebpf_handle_t handle, const uint8_t* name, uint32_t name_len
|
|||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->handle = reinterpret_cast<uint64_t>(handle);
|
||||
std::copy(name, name + name_length, request->name);
|
||||
return invoke_ioctl(device_handle, request_buffer);
|
||||
return invoke_ioctl(request_buffer);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -505,7 +308,7 @@ ebpf_api_unpin_object(const uint8_t* name, uint32_t name_length)
|
|||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->handle = UINT64_MAX;
|
||||
std::copy(name, name + name_length, request->name);
|
||||
return invoke_ioctl(device_handle, request_buffer);
|
||||
return invoke_ioctl(request_buffer);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -518,7 +321,7 @@ ebpf_api_get_pinned_map(const uint8_t* name, uint32_t name_length, ebpf_handle_t
|
|||
request->header.id = EBPF_OPERATION_GET_PINNING;
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
std::copy(name, name + name_length, request->name);
|
||||
auto result = invoke_ioctl(device_handle, request_buffer, reply);
|
||||
auto result = invoke_ioctl(request_buffer, reply);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
@ -546,7 +349,7 @@ ebpf_api_map_find_element(
|
|||
request->handle = reinterpret_cast<uint64_t>(handle);
|
||||
std::copy(key, key + key_size, request->key);
|
||||
|
||||
auto retval = invoke_ioctl(device_handle, request_buffer, reply_buffer);
|
||||
auto retval = invoke_ioctl(request_buffer, reply_buffer);
|
||||
|
||||
if (reply->header.id != ebpf_operation_id_t::EBPF_OPERATION_MAP_FIND_ELEMENT) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
@ -572,7 +375,7 @@ ebpf_api_map_update_element(
|
|||
std::copy(key, key + key_size, request->data);
|
||||
std::copy(value, value + value_size, request->data + key_size);
|
||||
|
||||
return invoke_ioctl(device_handle, request_buffer);
|
||||
return invoke_ioctl(request_buffer);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -586,7 +389,7 @@ ebpf_api_map_delete_element(ebpf_handle_t handle, uint32_t key_size, const uint8
|
|||
request->handle = (uint64_t)handle;
|
||||
std::copy(key, key + key_size, request->key);
|
||||
|
||||
return invoke_ioctl(device_handle, request_buffer);
|
||||
return invoke_ioctl(request_buffer);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -606,7 +409,7 @@ ebpf_api_get_next_map_key(ebpf_handle_t handle, uint32_t key_size, const uint8_t
|
|||
request->header.length = offsetof(ebpf_operation_map_get_next_key_request_t, previous_key);
|
||||
}
|
||||
|
||||
auto retval = invoke_ioctl(device_handle, request_buffer, reply_buffer);
|
||||
auto retval = invoke_ioctl(request_buffer, reply_buffer);
|
||||
|
||||
if (reply->header.id != ebpf_operation_id_t::EBPF_OPERATION_MAP_GET_NEXT_KEY) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
@ -626,7 +429,7 @@ ebpf_api_get_next_map(ebpf_handle_t previous_handle, ebpf_handle_t* next_handle)
|
|||
|
||||
_ebpf_operation_get_next_map_reply reply;
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply);
|
||||
uint32_t retval = invoke_ioctl(request, reply);
|
||||
if (retval == ERROR_SUCCESS) {
|
||||
*next_handle = reinterpret_cast<ebpf_handle_t>(reply.next_handle);
|
||||
}
|
||||
|
@ -636,21 +439,20 @@ ebpf_api_get_next_map(ebpf_handle_t previous_handle, ebpf_handle_t* next_handle)
|
|||
uint32_t
|
||||
ebpf_api_get_next_program(ebpf_handle_t previous_handle, ebpf_handle_t* next_handle)
|
||||
{
|
||||
_ebpf_operation_get_next_program_request request{
|
||||
sizeof(request),
|
||||
_ebpf_operation_get_next_program_request request{sizeof(request),
|
||||
ebpf_operation_id_t::EBPF_OPERATION_GET_NEXT_PROGRAM,
|
||||
reinterpret_cast<uint64_t>(previous_handle)};
|
||||
|
||||
_ebpf_operation_get_next_program_reply reply;
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply);
|
||||
uint32_t retval = invoke_ioctl(request, reply);
|
||||
if (retval == ERROR_SUCCESS) {
|
||||
*next_handle = reinterpret_cast<ebpf_handle_t>(reply.next_handle);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ebpf_result_t
|
||||
ebpf_api_map_query_definition(
|
||||
ebpf_handle_t handle,
|
||||
uint32_t* size,
|
||||
|
@ -659,20 +461,7 @@ ebpf_api_map_query_definition(
|
|||
uint32_t* value_size,
|
||||
uint32_t* max_entries)
|
||||
{
|
||||
_ebpf_operation_query_map_definition_request request{
|
||||
sizeof(request), ebpf_operation_id_t::EBPF_OPERATION_QUERY_MAP_DEFINITION, reinterpret_cast<uint64_t>(handle)};
|
||||
|
||||
_ebpf_operation_query_map_definition_reply reply;
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply);
|
||||
if (retval == ERROR_SUCCESS) {
|
||||
*size = reply.map_definition.size;
|
||||
*type = reply.map_definition.type;
|
||||
*key_size = reply.map_definition.key_size;
|
||||
*value_size = reply.map_definition.value_size;
|
||||
*max_entries = reply.map_definition.max_entries;
|
||||
}
|
||||
return retval;
|
||||
return query_map_definition(handle, size, type, key_size, value_size, max_entries);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -687,7 +476,7 @@ ebpf_api_program_query_information(
|
|||
|
||||
auto reply = reinterpret_cast<_ebpf_operation_query_program_information_reply*>(reply_buffer.data());
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply_buffer);
|
||||
uint32_t retval = invoke_ioctl(request, reply_buffer);
|
||||
if (retval != ERROR_SUCCESS) {
|
||||
return retval;
|
||||
}
|
||||
|
@ -723,7 +512,7 @@ ebpf_api_link_program(ebpf_handle_t program_handle, ebpf_attach_type_t attach_ty
|
|||
sizeof(request), EBPF_OPERATION_LINK_PROGRAM, reinterpret_cast<uint64_t>(program_handle), attach_type};
|
||||
ebpf_operation_link_program_reply_t reply;
|
||||
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply);
|
||||
uint32_t retval = invoke_ioctl(request, reply);
|
||||
if (retval != ERROR_SUCCESS) {
|
||||
return retval;
|
||||
}
|
||||
|
@ -742,5 +531,5 @@ ebpf_api_close_handle(ebpf_handle_t handle)
|
|||
ebpf_operation_close_handle_request_t request = {
|
||||
sizeof(request), EBPF_OPERATION_CLOSE_HANDLE, reinterpret_cast<uint64_t>(handle)};
|
||||
|
||||
return invoke_ioctl(device_handle, request);
|
||||
return invoke_ioctl(request);
|
||||
}
|
||||
|
|
|
@ -12,5 +12,8 @@ initialize_rpc_binding(void);
|
|||
RPC_STATUS
|
||||
clean_up_rpc_binding(void);
|
||||
|
||||
int
|
||||
ebpf_rpc_verify_program(ebpf_program_verify_info* info, const char** logs, uint32_t* logs_size);
|
||||
ebpf_result_t
|
||||
ebpf_rpc_verify_program(ebpf_program_verify_info* info, const char** logs, uint32_t* logs_size) noexcept;
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_rpc_load_program(ebpf_program_load_info* info, const char** logs, uint32_t* logs_size) noexcept;
|
|
@ -32,7 +32,7 @@ create_map_windows(
|
|||
if (options.mock_map_fds) {
|
||||
EbpfMapType type = get_map_type_windows(map_type);
|
||||
fd = create_map_crab(type, key_size, value_size, max_entries, options);
|
||||
cache_map_file_descriptor(map_type, key_size, value_size, fd);
|
||||
cache_map_file_descriptor(map_type, key_size, value_size, max_entries, fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <Windows.h>
|
||||
#include "api_common.hpp"
|
||||
#include "device_helper.hpp"
|
||||
#include "ebpf_protocol.h"
|
||||
#include "ebpf_result.h"
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100) // 'identifier' : unreferenced formal parameter
|
||||
#pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to
|
||||
|
@ -14,7 +18,7 @@
|
|||
#pragma warning(pop)
|
||||
|
||||
const char*
|
||||
allocate_error_string(const std::string& str, uint32_t* length = nullptr)
|
||||
allocate_error_string(const std::string& str, uint32_t* length) noexcept
|
||||
{
|
||||
char* error_message;
|
||||
size_t error_message_length = str.size() + 1;
|
||||
|
@ -36,7 +40,7 @@ convert_ebpf_program_to_bytes(const std::vector<ebpf_inst>& instructions)
|
|||
}
|
||||
|
||||
int
|
||||
get_file_size(const char* filename, size_t* byte_code_size)
|
||||
get_file_size(const char* filename, size_t* byte_code_size) noexcept
|
||||
{
|
||||
int result = 0;
|
||||
*byte_code_size = NULL;
|
||||
|
@ -49,3 +53,29 @@ get_file_size(const char* filename, size_t* byte_code_size)
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
query_map_definition(
|
||||
ebpf_handle_t handle,
|
||||
uint32_t* size,
|
||||
uint32_t* type,
|
||||
uint32_t* key_size,
|
||||
uint32_t* value_size,
|
||||
uint32_t* max_entries) noexcept
|
||||
{
|
||||
_ebpf_operation_query_map_definition_request request{
|
||||
sizeof(request), ebpf_operation_id_t::EBPF_OPERATION_QUERY_MAP_DEFINITION, reinterpret_cast<uint64_t>(handle)};
|
||||
|
||||
_ebpf_operation_query_map_definition_reply reply;
|
||||
|
||||
uint32_t result = invoke_ioctl(request, reply);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
*size = reply.map_definition.size;
|
||||
*type = reply.map_definition.type;
|
||||
*key_size = reply.map_definition.key_size;
|
||||
*value_size = reply.map_definition.value_size;
|
||||
*max_entries = reply.map_definition.max_entries;
|
||||
}
|
||||
|
||||
return windows_error_to_ebpf_result(result);
|
||||
}
|
||||
|
|
|
@ -7,34 +7,53 @@
|
|||
#include <stdexcept>
|
||||
#include "ebpf_api.h"
|
||||
#include "ebpf_execution_context.h"
|
||||
#include "ebpf_platform.h"
|
||||
#include "ebpf_result.h"
|
||||
#undef VOID
|
||||
#include "ebpf_helpers.h"
|
||||
#include "platform.hpp"
|
||||
extern "C"
|
||||
{
|
||||
#include "ubpf.h"
|
||||
}
|
||||
|
||||
typedef struct _map_cache
|
||||
{
|
||||
uintptr_t handle;
|
||||
EbpfMapDescriptor ebpf_map_descriptor;
|
||||
|
||||
_map_cache() {}
|
||||
|
||||
_map_cache(uintptr_t handle, EbpfMapDescriptor descriptor) : handle(handle), ebpf_map_descriptor(descriptor) {}
|
||||
|
||||
_map_cache(
|
||||
uintptr_t handle,
|
||||
int original_fd,
|
||||
uint32_t type,
|
||||
unsigned int key_size,
|
||||
unsigned int value_size,
|
||||
unsigned int max_entries,
|
||||
unsigned int inner_map_fd)
|
||||
: handle(handle)
|
||||
{
|
||||
ebpf_map_descriptor.original_fd = original_fd;
|
||||
ebpf_map_descriptor.type = type;
|
||||
ebpf_map_descriptor.key_size = key_size;
|
||||
ebpf_map_descriptor.value_size = value_size;
|
||||
ebpf_map_descriptor.max_entries = max_entries;
|
||||
ebpf_map_descriptor.inner_map_fd = inner_map_fd;
|
||||
}
|
||||
} map_cache_t;
|
||||
|
||||
const char*
|
||||
allocate_error_string(const std::string& str, uint32_t* length = nullptr);
|
||||
allocate_error_string(const std::string& str, uint32_t* length = nullptr) noexcept;
|
||||
|
||||
std::vector<uint8_t>
|
||||
convert_ebpf_program_to_bytes(const std::vector<ebpf_inst>& instructions);
|
||||
|
||||
int
|
||||
get_file_size(const char* filename, size_t* byte_code_size);
|
||||
get_file_size(const char* filename, size_t* byte_code_size) noexcept;
|
||||
|
||||
EbpfHelperPrototype
|
||||
get_helper_prototype_windows(unsigned int n);
|
||||
|
||||
int
|
||||
cache_map_handle(uint64_t handle, uint32_t type, uint32_t key_size, uint32_t value_size);
|
||||
cache_map_handle(uint64_t handle, uint32_t type, uint32_t key_size, uint32_t value_size, uint32_t max_entries);
|
||||
|
||||
size_t
|
||||
get_map_descriptor_size(void);
|
||||
|
@ -44,3 +63,70 @@ get_map_handle(int map_fd);
|
|||
|
||||
std::vector<uintptr_t>
|
||||
get_all_map_handles(void);
|
||||
|
||||
std::vector<map_cache_t>
|
||||
get_all_map_descriptors();
|
||||
|
||||
__forceinline ebpf_result_t
|
||||
windows_error_to_ebpf_result(uint32_t error)
|
||||
{
|
||||
ebpf_result_t result;
|
||||
|
||||
switch (error) {
|
||||
case ERROR_SUCCESS:
|
||||
result = EBPF_SUCCESS;
|
||||
break;
|
||||
|
||||
case ERROR_OUTOFMEMORY:
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
result = EBPF_NO_MEMORY;
|
||||
break;
|
||||
|
||||
case ERROR_NOT_FOUND:
|
||||
result = EBPF_ERROR_NOT_FOUND;
|
||||
break;
|
||||
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
result = EBPF_INVALID_ARGUMENT;
|
||||
break;
|
||||
|
||||
case ERROR_NO_MORE_ITEMS:
|
||||
result = EBPF_ERROR_NO_MORE_KEYS;
|
||||
break;
|
||||
|
||||
case ERROR_INVALID_HANDLE:
|
||||
result = EBPF_ERROR_INVALID_HANDLE;
|
||||
break;
|
||||
|
||||
case ERROR_NOT_SUPPORTED:
|
||||
result = EBPF_ERROR_NOT_SUPPORTED;
|
||||
break;
|
||||
|
||||
case ERROR_MORE_DATA:
|
||||
result = EBPF_ERROR_INSUFFICIENT_BUFFER;
|
||||
break;
|
||||
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
result = EBPF_FILE_NOT_FOUND;
|
||||
break;
|
||||
|
||||
case ERROR_ALREADY_INITIALIZED:
|
||||
result = EBPF_ALREADY_INITIALIZED;
|
||||
break;
|
||||
|
||||
default:
|
||||
result = EBPF_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
query_map_definition(
|
||||
ebpf_handle_t handle,
|
||||
uint32_t* size,
|
||||
uint32_t* type,
|
||||
uint32_t* key_size,
|
||||
uint32_t* value_size,
|
||||
uint32_t* max_entries) noexcept;
|
|
@ -169,6 +169,7 @@
|
|||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="device_helper.cpp" />
|
||||
<ClCompile Include="map_descriptors.cpp" />
|
||||
<ClCompile Include="api_common.cpp" />
|
||||
<ClCompile Include="windows_helpers.cpp" />
|
||||
|
@ -178,7 +179,7 @@
|
|||
<ClInclude Include="map_descriptors.hpp" />
|
||||
<ClInclude Include="api_common.hpp" />
|
||||
<ClInclude Include="tlv.h" />
|
||||
<ClInclude Include="windows_helpers.hpp" />
|
||||
<ClInclude Include="device_helper.hpp" />
|
||||
<ClInclude Include="windows_platform_common.hpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
<ClCompile Include="map_descriptors.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="device_helper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="tlv.h">
|
||||
|
@ -42,7 +45,7 @@
|
|||
<ClInclude Include="map_descriptors.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="windows_helpers.hpp">
|
||||
<ClInclude Include="device_helper.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Contains code to manage device for kernel mode execution context.
|
||||
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include "api_common.hpp"
|
||||
#include "ebpf_api.h"
|
||||
#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_xdp_program_data.h"
|
||||
#include "platform.h"
|
||||
#undef VOID
|
||||
#include "platform.hpp"
|
||||
|
||||
static ebpf_handle_t _device_handle = INVALID_HANDLE_VALUE;
|
||||
static std::mutex _mutex;
|
||||
|
||||
ebpf_result_t
|
||||
initialize_device_handle()
|
||||
{
|
||||
std::scoped_lock lock(_mutex);
|
||||
|
||||
if (_device_handle != INVALID_HANDLE_VALUE) {
|
||||
return EBPF_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
_device_handle = Platform::CreateFile(
|
||||
EBPF_DEVICE_WIN32_NAME,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
|
||||
if (_device_handle == INVALID_HANDLE_VALUE) {
|
||||
return windows_error_to_ebpf_result(GetLastError());
|
||||
}
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
clean_up_device_handle()
|
||||
{
|
||||
std::scoped_lock lock(_mutex);
|
||||
|
||||
if (_device_handle != INVALID_HANDLE_VALUE) {
|
||||
Platform::CloseHandle(_device_handle);
|
||||
_device_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
ebpf_handle_t
|
||||
get_device_handle()
|
||||
{
|
||||
if (_device_handle == INVALID_HANDLE_VALUE) {
|
||||
initialize_device_handle();
|
||||
}
|
||||
|
||||
return _device_handle;
|
||||
}
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ebpf_api.h"
|
||||
#include "platform.h"
|
||||
|
||||
// Device type
|
||||
#define EBPF_IOCTL_TYPE FILE_DEVICE_NETWORK
|
||||
|
||||
|
@ -18,9 +21,18 @@ typedef struct empty_reply
|
|||
|
||||
static empty_reply_t _empty_reply;
|
||||
|
||||
ebpf_result_t
|
||||
initialize_device_handle();
|
||||
|
||||
void
|
||||
clean_up_device_handle();
|
||||
|
||||
ebpf_handle_t
|
||||
get_device_handle();
|
||||
|
||||
template <typename request_t, typename reply_t = empty_reply_t>
|
||||
uint32_t
|
||||
invoke_ioctl(ebpf_handle_t handle, request_t& request, reply_t& reply = _empty_reply)
|
||||
invoke_ioctl(request_t& request, reply_t& reply = _empty_reply)
|
||||
{
|
||||
uint32_t actual_reply_size;
|
||||
uint32_t request_size;
|
||||
|
@ -56,7 +68,7 @@ invoke_ioctl(ebpf_handle_t handle, request_t& request, reply_t& reply = _empty_r
|
|||
}
|
||||
|
||||
auto result = Platform::DeviceIoControl(
|
||||
handle,
|
||||
get_device_handle(),
|
||||
IOCTL_EBPFCTL_METHOD_BUFFERED,
|
||||
request_ptr,
|
||||
request_size,
|
||||
|
@ -75,5 +87,3 @@ invoke_ioctl(ebpf_handle_t handle, request_t& request, reply_t& reply = _empty_r
|
|||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
extern ebpf_handle_t device_handle;
|
|
@ -11,9 +11,7 @@ cache_map_file_descriptors(const EbpfMapDescriptor* map_descriptors, uint32_t ma
|
|||
{
|
||||
for (uint32_t i = 0; i < map_descriptors_count; i++) {
|
||||
auto descriptor = map_descriptors[i];
|
||||
_map_file_descriptors.push_back(
|
||||
{(uintptr_t)descriptor.original_fd,
|
||||
{descriptor.original_fd, descriptor.type, descriptor.key_size, descriptor.value_size, 0}});
|
||||
_map_file_descriptors.emplace_back((uintptr_t)descriptor.original_fd, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +31,7 @@ get_map_cache_entry(uint64_t map_fd)
|
|||
}
|
||||
}
|
||||
|
||||
return _map_file_descriptors[0];
|
||||
throw std::runtime_error(std::string("Map cache entry for map fd ") + std::to_string(map_fd) + " not found.");
|
||||
}
|
||||
|
||||
EbpfMapDescriptor&
|
||||
|
@ -72,19 +70,32 @@ get_all_map_handles()
|
|||
return handles;
|
||||
}
|
||||
|
||||
void
|
||||
cache_map_file_descriptor(uint32_t type, uint32_t key_size, uint32_t value_size, int fd)
|
||||
std::vector<map_cache_t>
|
||||
get_all_map_descriptors()
|
||||
{
|
||||
_map_file_descriptors.push_back({(uintptr_t)fd, {fd, type, key_size, value_size, 0}});
|
||||
return _map_file_descriptors;
|
||||
}
|
||||
|
||||
void
|
||||
cache_map_file_descriptor(uint32_t type, uint32_t key_size, uint32_t value_size, uint32_t max_entries, int fd)
|
||||
{
|
||||
_map_file_descriptors.emplace_back((uintptr_t)fd, fd, type, key_size, value_size, max_entries, 0);
|
||||
}
|
||||
|
||||
void
|
||||
cache_map_file_descriptor_with_handle(
|
||||
uint32_t type, uint32_t key_size, uint32_t value_size, uint32_t max_entries, int fd, uintptr_t handle)
|
||||
{
|
||||
_map_file_descriptors.emplace_back(handle, fd, type, key_size, value_size, max_entries, 0);
|
||||
}
|
||||
|
||||
int
|
||||
cache_map_handle(uint64_t handle, uint32_t type, uint32_t key_size, uint32_t value_size)
|
||||
cache_map_handle(uint64_t handle, uint32_t type, uint32_t key_size, uint32_t value_size, uint32_t max_entries)
|
||||
{
|
||||
// TODO: Replace this with the CRT helper to create FD from handle once we
|
||||
// have real handles.
|
||||
int fd = static_cast<int>(_map_file_descriptors.size() + 1);
|
||||
_map_file_descriptors.push_back({handle, {fd, type, key_size, value_size, 0}});
|
||||
_map_file_descriptors.emplace_back(handle, fd, type, key_size, value_size, max_entries, 0);
|
||||
return static_cast<int>(_map_file_descriptors.size());
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,11 @@ void
|
|||
cache_map_file_descriptors(const EbpfMapDescriptor* map_descriptors, uint32_t map_descriptors_count);
|
||||
|
||||
void
|
||||
cache_map_file_descriptor(uint32_t type, uint32_t key_size, uint32_t value_size, int fd);
|
||||
cache_map_file_descriptor(uint32_t type, uint32_t key_size, uint32_t value_size, uint32_t max_entries, int fd);
|
||||
|
||||
void
|
||||
cache_map_file_descriptor_with_handle(
|
||||
uint32_t type, uint32_t key_size, uint32_t value_size, uint32_t max_entries, int fd, uintptr_t handle);
|
||||
|
||||
void
|
||||
clear_map_descriptors(void);
|
||||
|
@ -22,3 +26,6 @@ get_map_descriptor_at_index(int index);
|
|||
|
||||
uintptr_t
|
||||
get_map_handle_at_index(size_t index);
|
||||
|
||||
void
|
||||
clear_program_information_cache();
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include "ebpf_api.h"
|
||||
#include <vector>
|
||||
#include <Windows.h>
|
||||
#include "device_helper.hpp"
|
||||
#include "ebpf_bind_program_data.h"
|
||||
#include "ebpf_platform.h"
|
||||
#include "ebpf_program_types.h"
|
||||
|
@ -13,7 +15,6 @@
|
|||
#include "platform.h"
|
||||
#undef VOID
|
||||
#include "platform.hpp"
|
||||
#include "windows_helpers.hpp"
|
||||
|
||||
struct guid_compare
|
||||
{
|
||||
|
@ -24,9 +25,13 @@ struct guid_compare
|
|||
}
|
||||
};
|
||||
|
||||
thread_local std::map<GUID, ebpf_helper::ebpf_memory_ptr, guid_compare> g_program_information_cache;
|
||||
static thread_local std::map<GUID, ebpf_helper::ebpf_memory_ptr, guid_compare> _program_information_cache;
|
||||
|
||||
ebpf_handle_t device_handle = INVALID_HANDLE_VALUE;
|
||||
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)
|
||||
|
@ -36,7 +41,7 @@ get_program_information_data(ebpf_program_type_t program_type, ebpf_extension_da
|
|||
sizeof(request), ebpf_operation_id_t::EBPF_OPERATION_GET_PROGRAM_INFORMATION, program_type};
|
||||
|
||||
auto reply = reinterpret_cast<ebpf_operation_get_program_information_reply_t*>(reply_buffer.data());
|
||||
uint32_t retval = invoke_ioctl(device_handle, request, reply_buffer);
|
||||
uint32_t retval = invoke_ioctl(request, reply_buffer);
|
||||
if (retval != ERROR_SUCCESS) {
|
||||
return retval;
|
||||
}
|
||||
|
@ -70,8 +75,8 @@ get_program_type_info(const ebpf_program_information_t** info)
|
|||
size_t encoded_data_size = 0;
|
||||
|
||||
// See if we already have the program information cached.
|
||||
auto it = g_program_information_cache.find(*program_type);
|
||||
if (it == g_program_information_cache.end()) {
|
||||
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);
|
||||
|
@ -99,10 +104,10 @@ get_program_type_info(const ebpf_program_information_t** info)
|
|||
return result;
|
||||
}
|
||||
|
||||
g_program_information_cache[*program_type] = ebpf_helper::ebpf_memory_ptr(program_information);
|
||||
_program_information_cache[*program_type] = ebpf_helper::ebpf_memory_ptr(program_information);
|
||||
}
|
||||
|
||||
*info = (const ebpf_program_information_t*)g_program_information_cache[*program_type].get();
|
||||
*info = (const ebpf_program_information_t*)_program_information_cache[*program_type].get();
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include "api_common.hpp"
|
||||
#include "api_internal.h"
|
||||
#include "api_service.h"
|
||||
#include "ebpf_api.h"
|
||||
#include "device_helper.hpp"
|
||||
#include "ebpf_platform.h"
|
||||
#include "ebpf_protocol.h"
|
||||
#include "map_descriptors.hpp"
|
||||
|
@ -17,7 +16,189 @@ extern "C"
|
|||
}
|
||||
#include "Verifier.h"
|
||||
#include "verifier_service.h"
|
||||
#include "windows_helpers.hpp"
|
||||
|
||||
#define MAX_CODE_SIZE_IN_BYTES (32 * 1024) // 32 KB
|
||||
|
||||
static ebpf_result_t
|
||||
_build_helper_id_to_address_map(
|
||||
ebpf_handle_t program_handle, ebpf_code_buffer_t& byte_code, std::map<uint32_t, uint64_t>& helper_id_to_adddress)
|
||||
{
|
||||
ebpf_inst* instructions = reinterpret_cast<ebpf_inst*>(byte_code.data());
|
||||
for (size_t index = 0; index < byte_code.size() / sizeof(ebpf_inst); index++) {
|
||||
ebpf_inst& instruction = instructions[index];
|
||||
if (instruction.opcode != INST_OP_CALL) {
|
||||
continue;
|
||||
}
|
||||
helper_id_to_adddress[instruction.imm] = 0;
|
||||
}
|
||||
|
||||
if (helper_id_to_adddress.size() == 0)
|
||||
return EBPF_SUCCESS;
|
||||
|
||||
ebpf_protocol_buffer_t request_buffer(
|
||||
offsetof(ebpf_operation_resolve_helper_request_t, helper_id) + sizeof(uint32_t) * helper_id_to_adddress.size());
|
||||
|
||||
ebpf_protocol_buffer_t reply_buffer(
|
||||
offsetof(ebpf_operation_resolve_helper_reply_t, address) + sizeof(uint64_t) * helper_id_to_adddress.size());
|
||||
|
||||
auto request = reinterpret_cast<ebpf_operation_resolve_helper_request_t*>(request_buffer.data());
|
||||
auto reply = reinterpret_cast<ebpf_operation_resolve_helper_reply_t*>(reply_buffer.data());
|
||||
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_RESOLVE_HELPER;
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->program_handle = reinterpret_cast<uint64_t>(program_handle);
|
||||
|
||||
size_t index = 0;
|
||||
for (const auto& [helper_id, address] : helper_id_to_adddress) {
|
||||
request->helper_id[index++] = helper_id;
|
||||
}
|
||||
|
||||
uint32_t result = invoke_ioctl(request_buffer, reply_buffer);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return windows_error_to_ebpf_result(result);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
for (auto& [helper_id, address] : helper_id_to_adddress) {
|
||||
address = reply->address[index++];
|
||||
}
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
_resolve_ec_function(ebpf_ec_function_t function, uint64_t* address)
|
||||
{
|
||||
ebpf_operation_get_ec_function_request_t request = {sizeof(request), EBPF_OPERATION_GET_EC_FUNCTION, function};
|
||||
ebpf_operation_get_ec_function_reply_t reply;
|
||||
|
||||
uint32_t result = invoke_ioctl(request, reply);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return windows_error_to_ebpf_result(result);
|
||||
}
|
||||
|
||||
if (reply.header.id != ebpf_operation_id_t::EBPF_OPERATION_GET_EC_FUNCTION) {
|
||||
return EBPF_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*address = reply.address;
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
_resolve_maps_in_byte_code(ebpf_handle_t program_handle, ebpf_code_buffer_t& byte_code)
|
||||
{
|
||||
std::vector<size_t> instruction_offsets;
|
||||
std::vector<uint64_t> map_handles;
|
||||
|
||||
ebpf_inst* instructions = reinterpret_cast<ebpf_inst*>(byte_code.data());
|
||||
ebpf_inst* instruction_end = reinterpret_cast<ebpf_inst*>(byte_code.data() + byte_code.size());
|
||||
for (size_t index = 0; index < byte_code.size() / sizeof(ebpf_inst); index++) {
|
||||
ebpf_inst& first_instruction = instructions[index];
|
||||
ebpf_inst& second_instruction = instructions[index + 1];
|
||||
if (first_instruction.opcode != INST_OP_LDDW_IMM) {
|
||||
continue;
|
||||
}
|
||||
if (&instructions[index + 1] >= instruction_end) {
|
||||
return EBPF_INVALID_ARGUMENT;
|
||||
}
|
||||
index++;
|
||||
|
||||
// Check for LD_MAP flag
|
||||
if (first_instruction.src != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t imm =
|
||||
static_cast<uint64_t>(first_instruction.imm) | (static_cast<uint64_t>(second_instruction.imm) << 32);
|
||||
instruction_offsets.push_back(index - 1);
|
||||
map_handles.push_back(imm);
|
||||
}
|
||||
|
||||
if (map_handles.empty()) {
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
ebpf_protocol_buffer_t request_buffer(
|
||||
offsetof(ebpf_operation_resolve_map_request_t, map_handle) + sizeof(uint64_t) * map_handles.size());
|
||||
|
||||
ebpf_protocol_buffer_t reply_buffer(
|
||||
offsetof(ebpf_operation_resolve_map_reply_t, address) + sizeof(uint64_t) * map_handles.size());
|
||||
|
||||
auto request = reinterpret_cast<ebpf_operation_resolve_map_request_t*>(request_buffer.data());
|
||||
auto reply = reinterpret_cast<ebpf_operation_resolve_map_reply_t*>(reply_buffer.data());
|
||||
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_RESOLVE_MAP;
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->program_handle = reinterpret_cast<uint64_t>(program_handle);
|
||||
|
||||
for (size_t index = 0; index < map_handles.size(); index++) {
|
||||
if (map_handles[index] > get_map_descriptor_size()) {
|
||||
return EBPF_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
request->map_handle[index] = get_map_handle_at_index((int)map_handles[index] - 1);
|
||||
}
|
||||
|
||||
uint32_t result = invoke_ioctl(request_buffer, reply_buffer);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return windows_error_to_ebpf_result(result);
|
||||
}
|
||||
|
||||
for (size_t index = 0; index < map_handles.size(); index++) {
|
||||
ebpf_inst& first_instruction = instructions[instruction_offsets[index]];
|
||||
ebpf_inst& second_instruction = instructions[instruction_offsets[index] + 1];
|
||||
|
||||
// Clear LD_MAP flag
|
||||
first_instruction.src = 0;
|
||||
|
||||
// Replace handle with address
|
||||
uint64_t new_imm = reply->address[index];
|
||||
first_instruction.imm = static_cast<uint32_t>(new_imm);
|
||||
second_instruction.imm = static_cast<uint32_t>(new_imm >> 32);
|
||||
}
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
_query_and_cache_map_descriptors(fd_handle_map* handle_map, uint32_t handle_map_count)
|
||||
{
|
||||
ebpf_result_t result;
|
||||
EbpfMapDescriptor descriptor;
|
||||
|
||||
if (handle_map_count > 0) {
|
||||
for (uint32_t i = 0; i < handle_map_count; i++) {
|
||||
uint32_t size;
|
||||
descriptor = {0};
|
||||
result = query_map_definition(
|
||||
handle_map[i].handle,
|
||||
&size,
|
||||
&descriptor.type,
|
||||
&descriptor.key_size,
|
||||
&descriptor.value_size,
|
||||
&descriptor.max_entries);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
cache_map_file_descriptor_with_handle(
|
||||
descriptor.type,
|
||||
descriptor.key_size,
|
||||
descriptor.value_size,
|
||||
descriptor.max_entries,
|
||||
handle_map[i].file_descriptor,
|
||||
(uintptr_t)handle_map[i].handle);
|
||||
}
|
||||
}
|
||||
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
ebpf_clear_thread_local_storage() noexcept
|
||||
{
|
||||
clear_map_descriptors();
|
||||
clear_program_information_cache();
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_verify_program(
|
||||
|
@ -28,10 +209,9 @@ ebpf_verify_program(
|
|||
uint32_t byte_code_size,
|
||||
uint8_t* byte_code,
|
||||
const char** logs,
|
||||
uint32_t* logs_size)
|
||||
uint32_t* logs_size) noexcept
|
||||
{
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
int error = 0;
|
||||
|
||||
// Only kernel execution context supported currently.
|
||||
if (execution_context == execution_context_user_mode) {
|
||||
|
@ -45,12 +225,8 @@ ebpf_verify_program(
|
|||
cache_map_file_descriptors(map_descriptors, map_descriptors_count);
|
||||
}
|
||||
|
||||
// Verify the program
|
||||
error = verify_byte_code(program_type, byte_code, byte_code_size, logs, logs_size);
|
||||
|
||||
if (error != 0) {
|
||||
result = EBPF_VALIDATION_FAILED;
|
||||
}
|
||||
// Verify the program.
|
||||
result = verify_byte_code(program_type, byte_code, byte_code_size, logs, logs_size);
|
||||
} catch (const std::bad_alloc&) {
|
||||
result = EBPF_NO_MEMORY;
|
||||
} catch (std::runtime_error& err) {
|
||||
|
@ -64,3 +240,165 @@ ebpf_verify_program(
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_verify_and_load_program(
|
||||
const GUID* program_type,
|
||||
ebpf_handle_t program_handle,
|
||||
ebpf_execution_context_t execution_context,
|
||||
ebpf_execution_type_t execution_type,
|
||||
uint32_t handle_map_count,
|
||||
fd_handle_map* handle_map,
|
||||
uint32_t byte_code_size,
|
||||
uint8_t* byte_code,
|
||||
const char** error_message,
|
||||
uint32_t* error_message_size) noexcept
|
||||
{
|
||||
ebpf_result_t result = EBPF_SUCCESS;
|
||||
int error = 0;
|
||||
uint64_t log_function_address;
|
||||
struct ubpf_vm* vm = nullptr;
|
||||
ebpf_protocol_buffer_t request_buffer;
|
||||
ebpf_operation_load_code_request_t* request = nullptr;
|
||||
|
||||
// Only kernel execution context supported currently.
|
||||
if (execution_context == execution_context_user_mode) {
|
||||
return EBPF_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*error_message = nullptr;
|
||||
*error_message_size = 0;
|
||||
|
||||
clear_map_descriptors();
|
||||
|
||||
// Query map descriptors from execution context.
|
||||
try {
|
||||
result = _query_and_cache_map_descriptors(handle_map, handle_map_count);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Verify the program
|
||||
result = verify_byte_code(program_type, byte_code, byte_code_size, error_message, error_message_size);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (byte_code_size > MAX_CODE_SIZE_IN_BYTES) {
|
||||
result = EBPF_PROGRAM_TOO_LARGE;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
ebpf_code_buffer_t byte_code_buffer(byte_code, byte_code + byte_code_size);
|
||||
|
||||
result = _resolve_maps_in_byte_code(program_handle, byte_code_buffer);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
result = _resolve_ec_function(EBPF_EC_FUNCTION_LOG, &log_function_address);
|
||||
if (result != EBPF_SUCCESS) {
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (execution_type == EBPF_EXECUTION_JIT) {
|
||||
std::map<uint32_t, uint64_t> helper_id_to_adddress;
|
||||
result = _build_helper_id_to_address_map(program_handle, byte_code_buffer, helper_id_to_adddress);
|
||||
if (result != EBPF_SUCCESS)
|
||||
goto Exit;
|
||||
|
||||
ebpf_code_buffer_t machine_code(MAX_CODE_SIZE_IN_BYTES);
|
||||
size_t machine_code_size = machine_code.size();
|
||||
|
||||
// JIT code.
|
||||
vm = ubpf_create();
|
||||
if (vm == nullptr) {
|
||||
result = EBPF_JIT_COMPILATION_FAILED;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
for (const auto& [helper_id, address] : helper_id_to_adddress) {
|
||||
if (ubpf_register(vm, helper_id, nullptr, reinterpret_cast<void*>(address)) < 0) {
|
||||
result = EBPF_JIT_COMPILATION_FAILED;
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
ubpf_set_error_print(
|
||||
vm, reinterpret_cast<int (*)(FILE * stream, const char* format, ...)>(log_function_address));
|
||||
|
||||
if (ubpf_load(
|
||||
vm,
|
||||
byte_code_buffer.data(),
|
||||
static_cast<uint32_t>(byte_code_buffer.size()),
|
||||
const_cast<char**>(error_message)) < 0) {
|
||||
result = EBPF_JIT_COMPILATION_FAILED;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (ubpf_translate(vm, machine_code.data(), &machine_code_size, const_cast<char**>(error_message))) {
|
||||
result = EBPF_JIT_COMPILATION_FAILED;
|
||||
goto Exit;
|
||||
}
|
||||
machine_code.resize(machine_code_size);
|
||||
byte_code_buffer = machine_code;
|
||||
|
||||
if (*error_message != nullptr) {
|
||||
*error_message_size = (uint32_t)strlen(*error_message);
|
||||
}
|
||||
}
|
||||
|
||||
request_buffer.resize(offsetof(ebpf_operation_load_code_request_t, code) + byte_code_buffer.size());
|
||||
request = reinterpret_cast<ebpf_operation_load_code_request_t*>(request_buffer.data());
|
||||
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_LOAD_CODE;
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->program_handle = reinterpret_cast<uint64_t>(program_handle);
|
||||
request->code_type = execution_type == EBPF_EXECUTION_JIT ? EBPF_CODE_NATIVE : EBPF_CODE_EBPF;
|
||||
|
||||
std::copy(
|
||||
byte_code_buffer.begin(),
|
||||
byte_code_buffer.end(),
|
||||
request_buffer.begin() + offsetof(ebpf_operation_load_code_request_t, code));
|
||||
|
||||
error = invoke_ioctl(request_buffer);
|
||||
|
||||
if (error != ERROR_SUCCESS) {
|
||||
result = EBPF_PROGRAM_LOAD_FAILED;
|
||||
goto Exit;
|
||||
}
|
||||
} catch (const std::bad_alloc&) {
|
||||
result = EBPF_NO_MEMORY;
|
||||
} catch (std::runtime_error& err) {
|
||||
auto message = err.what();
|
||||
*error_message = allocate_error_string(message, error_message_size);
|
||||
|
||||
result = EBPF_VALIDATION_FAILED;
|
||||
} catch (...) {
|
||||
result = EBPF_FAILED;
|
||||
}
|
||||
|
||||
Exit:
|
||||
if (vm) {
|
||||
ubpf_destroy(vm);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ebpf_service_initialize() noexcept
|
||||
{
|
||||
// This is best effort. If device handle does not initialize,
|
||||
// it will be re-attempted before an IOCTL call is made.
|
||||
// This is needed to ensure the service can successfully start
|
||||
// even if the driver is not installed.
|
||||
initialize_device_handle();
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
ebpf_service_cleanup() noexcept
|
||||
{
|
||||
clean_up_device_handle();
|
||||
}
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "api_internal.h"
|
||||
#include "ebpf_api.h"
|
||||
#include "ebpf_execution_context.h"
|
||||
#include "ebpf_execution_type.h"
|
||||
#include "ebpf_result.h"
|
||||
#include "rpc_interface_h.h"
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_verify_program(
|
||||
|
@ -15,4 +19,26 @@ ebpf_verify_program(
|
|||
uint32_t byte_code_size,
|
||||
uint8_t* byte_code,
|
||||
const char** logs,
|
||||
uint32_t* logs_size);
|
||||
uint32_t* logs_size) noexcept;
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_verify_and_load_program(
|
||||
const GUID* program_type,
|
||||
ebpf_handle_t program_handle,
|
||||
ebpf_execution_context_t execution_context,
|
||||
ebpf_execution_type_t execution_type,
|
||||
uint32_t handle_map_count,
|
||||
fd_handle_map* handle_map,
|
||||
uint32_t byte_code_size,
|
||||
uint8_t* byte_code,
|
||||
const char** error_message,
|
||||
uint32_t* error_message_size) noexcept;
|
||||
|
||||
uint32_t
|
||||
ebpf_service_initialize() noexcept;
|
||||
|
||||
void
|
||||
ebpf_service_cleanup() noexcept;
|
||||
|
||||
void
|
||||
ebpf_clear_thread_local_storage() noexcept;
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\api_common;$(SolutionDir)libs\api;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)rpc_interface;$(SolutionDir)libs\api_common;$(SolutionDir)libs\api;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
|
@ -152,7 +152,7 @@
|
|||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)libs\api_common;$(SolutionDir)libs\api;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)rpc_interface;$(SolutionDir)libs\api_common;$(SolutionDir)libs\api;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
#include "tlv.h"
|
||||
#include "windows_platform_service.hpp"
|
||||
|
||||
static int
|
||||
analyze(raw_program& raw_prog, const char** error_message, uint32_t* error_message_size = nullptr)
|
||||
static ebpf_result_t
|
||||
_analyze(raw_program& raw_prog, const char** error_message, uint32_t* error_message_size = nullptr)
|
||||
{
|
||||
std::variant<InstructionSeq, std::string> prog_or_error = unmarshal(raw_prog);
|
||||
if (!std::holds_alternative<InstructionSeq>(prog_or_error)) {
|
||||
*error_message = allocate_error_string(std::get<std::string>(prog_or_error), error_message_size);
|
||||
return 1; // Error;
|
||||
return EBPF_VALIDATION_FAILED; // Error;
|
||||
}
|
||||
InstructionSeq& prog = std::get<InstructionSeq>(prog_or_error);
|
||||
|
||||
|
@ -43,12 +43,12 @@ analyze(raw_program& raw_prog, const char** error_message, uint32_t* error_messa
|
|||
(void)ebpf_verify_program(oss, prog, raw_prog.info, &options, &stats);
|
||||
|
||||
*error_message = allocate_error_string(oss.str(), error_message_size);
|
||||
return 1; // Error;
|
||||
return EBPF_VALIDATION_FAILED; // Error;
|
||||
}
|
||||
return 0; // Success.
|
||||
return EBPF_SUCCESS; // Success.
|
||||
}
|
||||
|
||||
int
|
||||
ebpf_result_t
|
||||
verify_byte_code(
|
||||
const GUID* program_type,
|
||||
const uint8_t* byte_code,
|
||||
|
@ -66,5 +66,5 @@ verify_byte_code(
|
|||
|
||||
raw_program raw_prog{file, section, instructions, info};
|
||||
|
||||
return analyze(raw_prog, error_message, error_message_size);
|
||||
return _analyze(raw_prog, error_message, error_message_size);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#undef VOID
|
||||
#include "platform.hpp"
|
||||
|
||||
int
|
||||
ebpf_result_t
|
||||
verify_byte_code(
|
||||
const GUID* program_type,
|
||||
const uint8_t* byte_code,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import "ebpf_execution_context.h";
|
||||
import "ebpf_execution_type.h";
|
||||
import "ebpf_result.h";
|
||||
import "stdint.h";
|
||||
import "wtypes.idl";
|
||||
|
@ -38,11 +39,14 @@ import "wtypes.idl";
|
|||
|
||||
typedef struct _ebpf_program_load_info
|
||||
{
|
||||
// Optional file name with full path.
|
||||
// Optional file name.
|
||||
[string] char* file_name;
|
||||
// Optional section name.
|
||||
[string] char* section_name;
|
||||
// Optional program name.
|
||||
[string] char* program_name;
|
||||
GUID program_type;
|
||||
ebpf_execution_type_t execution_type;
|
||||
file_handle_t program_handle;
|
||||
ebpf_execution_context_t execution_context;
|
||||
uint32_t map_count;
|
||||
|
@ -61,7 +65,7 @@ import "wtypes.idl";
|
|||
[ size_is(byte_code_size), ref ] uint8_t* byte_code;
|
||||
} ebpf_program_verify_info;
|
||||
|
||||
ebpf_result_t verify_and_jit_program(
|
||||
ebpf_result_t verify_and_load_program(
|
||||
[ in, ref ] ebpf_program_load_info * info,
|
||||
[ out, ref ] uint32_t * logs_size,
|
||||
[ out, size_is(, *logs_size), ref ] char** logs);
|
||||
|
|
|
@ -130,6 +130,7 @@
|
|||
<AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)libs\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DefaultCharType>Unsigned</DefaultCharType>
|
||||
<AdditionalOptions>/prefix server "ebpf_server_" /prefix client "ebpf_client_" %(AdditionalOptions)</AdditionalOptions>
|
||||
<MinimumTargetSystem>NT100</MinimumTargetSystem>
|
||||
</Midl>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
|
|
@ -152,9 +152,9 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\ebpfapi\rpc_client.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="platform.cpp" />
|
||||
<ClCompile Include="rpc_client.cpp" />
|
||||
<ClCompile Include="service_helper.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -184,8 +184,8 @@
|
|||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\libs\api\rpc_client.h" />
|
||||
<ClInclude Include="header.h" />
|
||||
<ClInclude Include="rpc_client.h" />
|
||||
<ClInclude Include="service_helper.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="rpc_client.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="platform.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -27,6 +24,9 @@
|
|||
<ClCompile Include="service_helper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ebpfapi\rpc_client.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -38,7 +38,7 @@
|
|||
<ClInclude Include="service_helper.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="rpc_client.h">
|
||||
<ClInclude Include="..\..\libs\api\rpc_client.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "ebpf_api.h"
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4100) // 'identifier' : unreferenced formal parameter
|
||||
#pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to
|
||||
// 'type2', possible loss of data
|
||||
#undef VOID
|
||||
#include "ebpf_verifier.hpp"
|
||||
#pragma warning(pop)
|
||||
#include "ebpf_windows.h"
|
||||
#include "header.h"
|
||||
#include "rpc_interface_c.c"
|
||||
|
||||
#pragma comment(lib, "Rpcrt4.lib")
|
||||
|
||||
static RPC_WSTR _string_binding = nullptr;
|
||||
static const WCHAR* _protocol_sequence = L"ncacn_np";
|
||||
|
||||
#define RPC_SERVER_ENDPOINT L"\\pipe\\ebpf_service"
|
||||
|
||||
int
|
||||
ebpf_rpc_verify_program(ebpf_program_verify_info* info, const char** logs, uint32_t* logs_size)
|
||||
{
|
||||
unsigned long code;
|
||||
int result;
|
||||
|
||||
RpcTryExcept { result = (int)ebpf_client_verify_program(info, logs_size, const_cast<char**>(logs)); }
|
||||
RpcExcept(RpcExceptionFilter(RpcExceptionCode()))
|
||||
{
|
||||
code = RpcExceptionCode();
|
||||
printf("ebpf_rpc_verify_program: runtime reported exception 0x%lx = %ld\n", code, code);
|
||||
result = (int)EBPF_FAILED;
|
||||
}
|
||||
RpcEndExcept
|
||||
|
||||
printf("ebpf_rpc_verify_program: got return code %d from the server\n\n", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RPC_STATUS
|
||||
initialize_rpc_binding()
|
||||
{
|
||||
RPC_STATUS status;
|
||||
RPC_WSTR uuid = nullptr;
|
||||
const WCHAR* network_address = nullptr;
|
||||
RPC_WSTR options = nullptr;
|
||||
|
||||
status = RpcStringBindingCompose(
|
||||
uuid,
|
||||
(RPC_WSTR)_protocol_sequence,
|
||||
(RPC_WSTR)network_address,
|
||||
(RPC_WSTR)RPC_SERVER_ENDPOINT,
|
||||
options,
|
||||
&_string_binding);
|
||||
|
||||
if (status != RPC_S_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return RpcBindingFromStringBinding(_string_binding, &ebpf_service_interface_handle);
|
||||
}
|
||||
|
||||
RPC_STATUS
|
||||
clean_up_rpc_binding()
|
||||
{
|
||||
RPC_STATUS status = RpcStringFree(&_string_binding);
|
||||
if (status != RPC_S_OK) {
|
||||
printf("RpcStringFree failed with error %d\n", status);
|
||||
}
|
||||
|
||||
status = RpcBindingFree(&ebpf_service_interface_handle);
|
||||
if (status != RPC_S_OK) {
|
||||
printf("RpcBindingFree failed with error %d\n", status);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
|
@ -80,7 +80,7 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)libs\api;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)libs\api;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
|
@ -98,7 +98,7 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)libs\api;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)libs\api;$(OutDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mock.h"
|
||||
#include "api_service.h"
|
||||
#include "ebpf_api.h"
|
||||
#include "mock.h"
|
||||
#include "rpc_interface_h.h"
|
||||
|
||||
std::function<decltype(CreateFileW)> create_file_handler;
|
||||
std::function<decltype(DeviceIoControl)> device_io_control_handler;
|
||||
std::function<decltype(CloseHandle)> close_handle_handler;
|
||||
|
@ -59,3 +62,29 @@ CloseHandle(_In_ _Post_ptr_invalid_ ebpf_handle_t handle)
|
|||
}
|
||||
|
||||
} // namespace Platform
|
||||
|
||||
// RPC related mock functions.
|
||||
|
||||
RPC_STATUS
|
||||
initialize_rpc_binding() { return RPC_S_OK; }
|
||||
|
||||
RPC_STATUS
|
||||
clean_up_rpc_binding() { return RPC_S_OK; }
|
||||
|
||||
ebpf_result_t
|
||||
ebpf_rpc_load_program(ebpf_program_load_info* info, const char** logs, uint32_t* logs_size)
|
||||
{
|
||||
// Short circuit rpc call to service lib.
|
||||
|
||||
return ebpf_verify_and_load_program(
|
||||
&info->program_type,
|
||||
info->program_handle,
|
||||
info->execution_context,
|
||||
info->execution_type,
|
||||
info->map_count,
|
||||
info->handle_map,
|
||||
info->byte_code_size,
|
||||
info->byte_code,
|
||||
const_cast<const char**>(logs),
|
||||
logs_size);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче