Merged PR 4216677: Add test code for bind hook
Add test code for bind hook
This commit is contained in:
Родитель
f974145fbc
Коммит
b2312a4790
|
@ -42,6 +42,8 @@ extern "C" {
|
|||
const char* section_name,
|
||||
ebpf_execution_type_t execution_type,
|
||||
ebpf_handle_t* handle,
|
||||
uint32_t* count_of_map_handles,
|
||||
ebpf_handle_t* map_handles,
|
||||
const char** error_message);
|
||||
|
||||
/**
|
||||
|
@ -105,6 +107,22 @@ extern "C" {
|
|||
uint32_t key_size,
|
||||
const uint8_t* key);
|
||||
|
||||
/**
|
||||
* @brief Return the next key in an eBPF map.
|
||||
* @param[in] handle Handle to eBPF map.
|
||||
* @param[in] key_size Size of the key buffer.
|
||||
* @param[in] previous_key Pointer to buffer containing
|
||||
previous key or NULL to restart enumeration.
|
||||
* @param[out] next_key Pointer to buffer that contains next
|
||||
* key on success.
|
||||
* @retval ERROR_NO_MORE_ITEMS previous_key was the last key.
|
||||
* @retval ERROR_NOT_FOUND previous_key was deleted.
|
||||
*/
|
||||
uint32_t ebpf_api_map_next_key(ebpf_handle_t handle,
|
||||
uint32_t key_size,
|
||||
const uint8_t* previous_key,
|
||||
uint8_t* next_key);
|
||||
|
||||
/**
|
||||
* @brief Enumerate through eBPF maps.
|
||||
* @param[in] previous_handle Handle to previous eBPF map or
|
||||
|
|
|
@ -55,6 +55,10 @@ ebpf_error_code_t ebpf_core_protocol_map_delete_element(
|
|||
_In_ const struct _ebpf_operation_map_delete_element_request* request,
|
||||
_Inout_ void* reply);
|
||||
|
||||
ebpf_error_code_t ebpf_core_protocol_map_get_next_key(
|
||||
_In_ const struct _ebpf_operation_map_next_key_request* request,
|
||||
_Inout_ struct _ebpf_operation_map_next_key_reply* reply);
|
||||
|
||||
ebpf_error_code_t ebpf_core_protocol_enumerate_maps(
|
||||
_In_ const struct _ebpf_operation_enumerate_maps_request* request,
|
||||
_Inout_ struct _ebpf_operation_enumerate_maps_reply* reply);
|
||||
|
|
|
@ -20,6 +20,7 @@ typedef struct _ebpf_map_function_table
|
|||
uint8_t* (*lookup_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key);
|
||||
ebpf_error_code_t (*update_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_ const uint8_t* value);
|
||||
ebpf_error_code_t (*delete_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key);
|
||||
ebpf_error_code_t (*next_key)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* previous_key, _Out_ uint8_t* next_key);
|
||||
} ebpf_map_function_table_t;
|
||||
|
||||
extern ebpf_map_function_table_t ebpf_map_function_tables[EBPF_MAP_TYPE_ARRAY + 1];
|
|
@ -45,6 +45,7 @@ void ebpf_hash_table_destroy(ebpf_hash_table_t* hash_table);
|
|||
ebpf_error_code_t ebpf_hash_table_lookup(ebpf_hash_table_t* hash_table, const uint8_t* key, uint8_t** value);
|
||||
ebpf_error_code_t ebpf_hash_table_update(ebpf_hash_table_t* hash_table, const uint8_t* key, const uint8_t* value);
|
||||
ebpf_error_code_t ebpf_hash_table_delete(ebpf_hash_table_t* hash_table, const uint8_t* key);
|
||||
ebpf_error_code_t ebpf_hash_table_next_key(ebpf_hash_table_t* hash_table, const uint8_t* previous_key, uint8_t* next_key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ typedef enum _ebpf_operation_id {
|
|||
EBPF_OPERATION_MAP_LOOKUP_ELEMENT,
|
||||
EBPF_OPERATION_MAP_UPDATE_ELEMENT,
|
||||
EBPF_OPERATION_MAP_DELETE_ELEMENT,
|
||||
EBPF_OPERATION_MAP_NEXT_KEY,
|
||||
EBPF_OPERATION_ENUMERATE_MAPS,
|
||||
EBPF_OPERATION_QUERY_MAP_DEFINITION,
|
||||
} ebpf_operation_id_t;
|
||||
|
@ -135,3 +136,15 @@ typedef struct _ebpf_operation_query_map_definition_reply {
|
|||
struct _ebpf_operation_header header;
|
||||
struct _ebpf_map_definition map_definition;
|
||||
} ebpf_operation_query_map_definition_reply;
|
||||
|
||||
typedef struct _ebpf_operation_map_next_key_request {
|
||||
struct _ebpf_operation_header header;
|
||||
uint64_t handle;
|
||||
uint8_t previous_key[1];
|
||||
} ebpf_operation_map_next_key_request_t;
|
||||
|
||||
typedef struct _ebpf_operation_map_next_key_reply {
|
||||
struct _ebpf_operation_header header;
|
||||
uint64_t handle;
|
||||
uint8_t next_key[1];
|
||||
} ebpf_operation_map_next_key_reply_t;
|
||||
|
|
|
@ -39,6 +39,9 @@ typedef enum _ebpf_error_code
|
|||
EBPF_ERROR_NOT_FOUND,
|
||||
EBPF_ERROR_INVALID_PARAMETER,
|
||||
EBPF_ERROR_BLOCKED_BY_POLICY,
|
||||
EBPF_ERROR_NO_MORE_KEYS,
|
||||
EBPF_ERROR_INVALID_HANDLE,
|
||||
EBPF_ERROR_NOT_SUPPORTED
|
||||
} ebpf_error_code_t;
|
||||
|
||||
typedef struct _ebpf_map_definition {
|
||||
|
|
|
@ -264,7 +264,13 @@ static uint32_t resolve_maps_in_byte_code(std::vector<uint8_t>& byte_code)
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t ebpf_api_load_program(const char* file_name, const char* section_name, ebpf_execution_type_t execution_type, ebpf_handle_t* handle, const char** error_message)
|
||||
uint32_t ebpf_api_load_program(const char* file_name,
|
||||
const char* section_name,
|
||||
ebpf_execution_type_t execution_type,
|
||||
ebpf_handle_t* handle,
|
||||
uint32_t* count_of_map_handles,
|
||||
ebpf_handle_t* map_handles,
|
||||
const char** error_message)
|
||||
{
|
||||
std::vector<uint8_t> byte_code(MAX_CODE_SIZE);
|
||||
size_t byte_code_size = byte_code.size();
|
||||
|
@ -279,6 +285,10 @@ uint32_t ebpf_api_load_program(const char* file_name, const char* section_name,
|
|||
{
|
||||
ubpf_destroy(vm);
|
||||
}
|
||||
for (auto& map : _map_file_descriptors)
|
||||
{
|
||||
ebpf_api_delete_map(reinterpret_cast<ebpf_handle_t>(map.handle));
|
||||
}
|
||||
});
|
||||
|
||||
uint32_t result;
|
||||
|
@ -305,6 +315,18 @@ uint32_t ebpf_api_load_program(const char* file_name, const char* section_name,
|
|||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (_map_file_descriptors.size() > *count_of_map_handles)
|
||||
{
|
||||
return ERROR_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
*count_of_map_handles = 0;
|
||||
for (const auto& map : _map_file_descriptors)
|
||||
{
|
||||
map_handles[*count_of_map_handles] = reinterpret_cast<HANDLE>(map.handle);
|
||||
(*count_of_map_handles)++;
|
||||
}
|
||||
|
||||
byte_code.resize(byte_code_size);
|
||||
result = resolve_maps_in_byte_code(byte_code);
|
||||
if (result != ERROR_SUCCESS)
|
||||
|
@ -368,6 +390,10 @@ uint32_t ebpf_api_load_program(const char* file_name, const char* section_name,
|
|||
|
||||
*handle = reinterpret_cast<ebpf_handle_t>(reply.handle);
|
||||
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
_map_file_descriptors.clear();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -378,7 +404,13 @@ void ebpf_api_free_error_message(const char* error_message)
|
|||
|
||||
void ebpf_api_unload_program(ebpf_handle_t handle)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
_ebpf_operation_unload_code_request request{
|
||||
sizeof(request),
|
||||
ebpf_operation_id_t::EBPF_OPERATION_UNLOAD_CODE,
|
||||
reinterpret_cast<uint64_t>(handle) };
|
||||
|
||||
invoke_ioctl(device_handle, request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -458,6 +490,39 @@ uint32_t ebpf_api_map_delete_element(ebpf_handle_t handle, uint32_t key_size, co
|
|||
return invoke_ioctl(device_handle, request_buffer);
|
||||
}
|
||||
|
||||
uint32_t ebpf_api_map_next_key(ebpf_handle_t handle, uint32_t key_size, const uint8_t* previous_key, uint8_t* next_key)
|
||||
{
|
||||
std::vector<uint8_t> request_buffer(offsetof(ebpf_operation_map_next_key_request_t, previous_key) + key_size);
|
||||
std::vector<uint8_t> reply_buffer(offsetof(ebpf_operation_map_next_key_reply_t, next_key) + key_size);
|
||||
auto request = reinterpret_cast<ebpf_operation_map_next_key_request_t*>(request_buffer.data());
|
||||
auto reply = reinterpret_cast<ebpf_operation_map_next_key_reply_t*>(reply_buffer.data());
|
||||
|
||||
request->header.length = static_cast<uint16_t>(request_buffer.size());
|
||||
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_MAP_NEXT_KEY;
|
||||
request->handle = reinterpret_cast<uint64_t>(handle);
|
||||
if (previous_key)
|
||||
{
|
||||
std::copy(previous_key, previous_key + key_size, request->previous_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
request->header.length = offsetof(ebpf_operation_map_next_key_request_t, previous_key);
|
||||
}
|
||||
|
||||
auto retval = invoke_ioctl(device_handle, request_buffer, reply_buffer);
|
||||
|
||||
if (reply->header.id != ebpf_operation_id_t::EBPF_OPERATION_MAP_NEXT_KEY)
|
||||
{
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (retval == ERROR_SUCCESS)
|
||||
{
|
||||
std::copy(reply->next_key, reply->next_key + key_size, next_key);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
uint32_t ebpf_api_map_enumerate(ebpf_handle_t previous_handle, ebpf_handle_t* next_handle)
|
||||
{
|
||||
_ebpf_operation_enumerate_maps_request request{
|
||||
|
|
|
@ -33,9 +33,20 @@ constexpr EbpfContextDescriptor xdp_context_descriptor = {
|
|||
const EbpfProgramType windows_xdp_program_type =
|
||||
PTYPE("xdp", xdp_context_descriptor, EBPF_PROGRAM_TYPE_XDP, {"xdp"});
|
||||
|
||||
constexpr EbpfContextDescriptor bind_context_descriptor = {
|
||||
43, // Size of ctx struct.
|
||||
0, // Offset into ctx struct of pointer to data, or -1 if none.
|
||||
8, // Offset into ctx struct of pointer to end of data, or -1 if none.
|
||||
-1, // Offset into ctx struct of pointer to metadata, or -1 if none.
|
||||
};
|
||||
|
||||
const EbpfProgramType windows_bind_program_type =
|
||||
PTYPE("bind", bind_context_descriptor, EBPF_PROGRAM_TYPE_BIND, { "bind" });
|
||||
|
||||
const std::vector<EbpfProgramType> windows_program_types = {
|
||||
PTYPE("unspecified", {0}, EBPF_PROGRAM_TYPE_UNSPECIFIED, {}),
|
||||
windows_xdp_program_type,
|
||||
windows_bind_program_type,
|
||||
};
|
||||
|
||||
static EbpfProgramType get_program_type_windows(const std::string& section, const std::string&)
|
||||
|
|
|
@ -201,6 +201,10 @@ static ebpf_error_code_t _ebpf_core_delete_code_entry(uint64_t handle)
|
|||
_ebpf_core_code_entry_table[handle] = NULL;
|
||||
retval = EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
ebpf_lock_unlock(&_ebpf_core_code_entry_table_lock, &state);
|
||||
return retval;
|
||||
}
|
||||
|
@ -250,12 +254,15 @@ ebpf_core_protocol_attach_code(
|
|||
}
|
||||
|
||||
code = _ebpf_core_find_user_code(request->handle);
|
||||
if (code)
|
||||
if (!code)
|
||||
{
|
||||
retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
code->hook_point = request->hook;
|
||||
_ebpf_core_set_hook_entry(code, code->hook_point);
|
||||
retval = EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
Done:
|
||||
return retval;
|
||||
|
@ -272,13 +279,17 @@ ebpf_core_protocol_detach_code(
|
|||
UNREFERENCED_PARAMETER(reply);
|
||||
|
||||
code = _ebpf_core_find_user_code(request->handle);
|
||||
if (code)
|
||||
if (!code)
|
||||
{
|
||||
retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
_ebpf_core_set_hook_entry(NULL, code->hook_point);
|
||||
code->hook_point = EBPF_PROGRAM_TYPE_UNSPECIFIED;
|
||||
retval = EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
Done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -401,7 +412,7 @@ ebpf_error_code_t ebpf_core_protocol_resolve_map(
|
|||
}
|
||||
else
|
||||
{
|
||||
return EBPF_ERROR_NOT_FOUND;
|
||||
return EBPF_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,7 +444,8 @@ ebpf_error_code_t ebpf_core_invoke_hook(
|
|||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
return EBPF_ERROR_NOT_FOUND;
|
||||
// Nothing to do if no hook is registered.
|
||||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
ebpf_error_code_t ebpf_core_protocol_create_map(
|
||||
|
@ -447,12 +459,12 @@ ebpf_error_code_t ebpf_core_protocol_create_map(
|
|||
|
||||
if (type >= RTL_COUNT_OF(ebpf_map_function_tables))
|
||||
{
|
||||
return EBPF_ERROR_NOT_FOUND;
|
||||
return EBPF_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (ebpf_map_function_tables[type].create_map == NULL)
|
||||
{
|
||||
retval = EBPF_ERROR_NOT_FOUND;
|
||||
retval = EBPF_ERROR_NOT_SUPPORTED;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
|
@ -494,7 +506,7 @@ ebpf_error_code_t ebpf_core_protocol_map_lookup_element(
|
|||
map = _ebpf_core_find_map_entry(request->handle);
|
||||
if (!map)
|
||||
{
|
||||
retval = EBPF_ERROR_NOT_FOUND;
|
||||
retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
|
@ -538,7 +550,7 @@ ebpf_error_code_t ebpf_core_protocol_map_update_element(
|
|||
map = _ebpf_core_find_map_entry(request->handle);
|
||||
if (!map)
|
||||
{
|
||||
retval = EBPF_ERROR_NOT_FOUND;
|
||||
retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
|
@ -568,7 +580,7 @@ ebpf_error_code_t ebpf_core_protocol_map_delete_element(
|
|||
map = _ebpf_core_find_map_entry(request->handle);
|
||||
if (!map)
|
||||
{
|
||||
retval = EBPF_ERROR_NOT_FOUND;
|
||||
retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
|
@ -586,6 +598,58 @@ Done:
|
|||
return retval;
|
||||
}
|
||||
|
||||
ebpf_error_code_t ebpf_core_protocol_map_get_next_key(
|
||||
_In_ const ebpf_operation_map_next_key_request_t* request,
|
||||
_Inout_ ebpf_operation_map_next_key_reply_t* reply)
|
||||
{
|
||||
ebpf_error_code_t retval;
|
||||
ebpf_core_map_t* map = NULL;
|
||||
size_t type;
|
||||
const uint8_t* previous_key;
|
||||
uint8_t* next_key = NULL;
|
||||
|
||||
map = _ebpf_core_find_map_entry(request->handle);
|
||||
if (!map)
|
||||
{
|
||||
retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
type = map->ebpf_map_definition.type;
|
||||
if (ebpf_map_function_tables[type].next_key == NULL)
|
||||
{
|
||||
retval = EBPF_ERROR_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
// If request length shows zero key, treat as restart.
|
||||
if (request->header.length == RTL_OFFSET_OF(ebpf_operation_map_next_key_request_t, previous_key))
|
||||
{
|
||||
previous_key = NULL;
|
||||
}
|
||||
else if (request->header.length < (RTL_OFFSET_OF(ebpf_operation_map_next_key_request_t, previous_key) + map->ebpf_map_definition.key_size))
|
||||
{
|
||||
retval = EBPF_ERROR_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_key = request->previous_key;
|
||||
}
|
||||
|
||||
next_key = reply->next_key;
|
||||
if (reply->header.length < (RTL_OFFSET_OF(ebpf_operation_map_next_key_reply_t, next_key) + map->ebpf_map_definition.key_size))
|
||||
{
|
||||
retval = EBPF_ERROR_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
retval = ebpf_map_function_tables[type].next_key(map, previous_key, next_key);
|
||||
|
||||
Done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
ebpf_error_code_t
|
||||
ebpf_core_protocol_enumerate_maps(
|
||||
_In_ const struct _ebpf_operation_enumerate_maps_request* request,
|
||||
|
@ -625,7 +689,7 @@ ebpf_core_protocol_query_map_definition(
|
|||
_In_ const struct _ebpf_operation_query_map_definition_request* request,
|
||||
_Inout_ struct _ebpf_operation_query_map_definition_reply* reply)
|
||||
{
|
||||
ebpf_error_code_t retval = EBPF_ERROR_NOT_FOUND;
|
||||
ebpf_error_code_t retval = EBPF_ERROR_INVALID_HANDLE;
|
||||
ebpf_core_map_t* map = NULL;
|
||||
|
||||
map = _ebpf_core_find_map_entry(request->handle);
|
||||
|
|
|
@ -66,7 +66,7 @@ static uint8_t* ebpf_lookup_array_map_entry(
|
|||
return &map->data[key_value * map->ebpf_map_definition.value_size];
|
||||
}
|
||||
|
||||
static ebpf_error_code_t ebpf_update_array_map(
|
||||
static ebpf_error_code_t ebpf_update_array_map_entry(
|
||||
_In_ ebpf_core_map_t* map,
|
||||
_In_ const uint8_t* key,
|
||||
_In_ const uint8_t* data)
|
||||
|
@ -85,7 +85,7 @@ static ebpf_error_code_t ebpf_update_array_map(
|
|||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static ebpf_error_code_t ebpf_delete_array_entry(
|
||||
static ebpf_error_code_t ebpf_delete_array_map_entry(
|
||||
_In_ ebpf_core_map_t* map,
|
||||
_In_ const uint8_t* key)
|
||||
{
|
||||
|
@ -126,6 +126,8 @@ ebpf_core_map_t* ebpf_create_hash_map(
|
|||
{
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ebpf_lock_create(&map->lock);
|
||||
retval = EBPF_ERROR_SUCCESS;
|
||||
|
||||
Done:
|
||||
|
@ -144,6 +146,7 @@ Done:
|
|||
static void ebpf_delete_hash_map(
|
||||
_In_ ebpf_core_map_t* map)
|
||||
{
|
||||
ebpf_lock_destroy(&map->lock);
|
||||
ebpf_hash_table_destroy((ebpf_hash_table_t*)map->data);
|
||||
ebpf_free(map);
|
||||
}
|
||||
|
@ -167,7 +170,7 @@ static uint8_t* ebpf_lookup_hash_map_entry(
|
|||
return value;
|
||||
}
|
||||
|
||||
static ebpf_error_code_t ebpf_update_hash_map(
|
||||
static ebpf_error_code_t ebpf_update_hash_map_entry(
|
||||
_In_ ebpf_core_map_t* map,
|
||||
_In_ const uint8_t* key,
|
||||
_In_ const uint8_t* data)
|
||||
|
@ -183,7 +186,7 @@ static ebpf_error_code_t ebpf_update_hash_map(
|
|||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static ebpf_error_code_t ebpf_delete_hash_entry(
|
||||
static ebpf_error_code_t ebpf_delete_hash_map_entry(
|
||||
_In_ ebpf_core_map_t* map,
|
||||
_In_ const uint8_t* key)
|
||||
{
|
||||
|
@ -199,6 +202,22 @@ static ebpf_error_code_t ebpf_delete_hash_entry(
|
|||
|
||||
}
|
||||
|
||||
static ebpf_error_code_t ebpf_next_hash_map_key(
|
||||
_In_ ebpf_core_map_t* map,
|
||||
_In_ const uint8_t* previous_key,
|
||||
_Out_ uint8_t* next_key)
|
||||
{
|
||||
ebpf_error_code_t result;
|
||||
ebpf_lock_state_t lock_state;
|
||||
if (!map || !next_key)
|
||||
return EBPF_ERROR_INVALID_PARAMETER;
|
||||
|
||||
ebpf_lock_lock(&map->lock, &lock_state);
|
||||
result = ebpf_hash_table_next_key((ebpf_hash_table_t*)map->data, previous_key, next_key);
|
||||
ebpf_lock_unlock(&map->lock, &lock_state);
|
||||
return result;
|
||||
}
|
||||
|
||||
ebpf_map_function_table_t ebpf_map_function_tables[] =
|
||||
{
|
||||
{ // EBPF_MAP_TYPE_UNSPECIFIED
|
||||
|
@ -208,14 +227,16 @@ ebpf_map_function_table_t ebpf_map_function_tables[] =
|
|||
ebpf_create_hash_map,
|
||||
ebpf_delete_hash_map,
|
||||
ebpf_lookup_hash_map_entry,
|
||||
ebpf_update_hash_map,
|
||||
ebpf_delete_hash_entry
|
||||
ebpf_update_hash_map_entry,
|
||||
ebpf_delete_hash_map_entry,
|
||||
ebpf_next_hash_map_key
|
||||
},
|
||||
{ // EBPF_MAP_TYPE_ARRAY
|
||||
ebpf_create_array_map,
|
||||
ebpf_delete_array_map,
|
||||
ebpf_lookup_array_map_entry,
|
||||
ebpf_update_array_map,
|
||||
ebpf_delete_array_entry
|
||||
ebpf_update_array_map_entry,
|
||||
ebpf_delete_array_map_entry,
|
||||
NULL
|
||||
},
|
||||
};
|
|
@ -253,10 +253,58 @@ Done:
|
|||
|
||||
ebpf_error_code_t ebpf_hash_table_delete(ebpf_hash_table_t* hash_table, const uint8_t* key)
|
||||
{
|
||||
PRTL_AVL_TABLE table = NULL;
|
||||
BOOLEAN result;
|
||||
RTL_AVL_TABLE* table = (RTL_AVL_TABLE*)hash_table;
|
||||
|
||||
result = RtlDeleteElementGenericTableAvl(table, (uint8_t*)key);
|
||||
return result == FALSE ? EBPF_ERROR_NOT_FOUND : EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
ebpf_error_code_t ebpf_hash_table_next_key(ebpf_hash_table_t* hash_table, const uint8_t* previous_key, uint8_t* next_key)
|
||||
{
|
||||
RTL_AVL_TABLE* table = (RTL_AVL_TABLE*)hash_table;
|
||||
uint8_t* entry;
|
||||
size_t sizes = (size_t)table->TableContext;
|
||||
uint16_t key_size = (uint16_t)(sizes >> 16);
|
||||
void* restart_key;
|
||||
|
||||
if (!previous_key)
|
||||
{
|
||||
entry = RtlEnumerateGenericTableAvl(table, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note - We need a better option to resume the search when the element was deleted.
|
||||
entry = RtlLookupFirstMatchingElementGenericTableAvl(table, (void*)previous_key, &restart_key);
|
||||
if (!entry)
|
||||
{
|
||||
// Entry deleted.
|
||||
|
||||
// Start at the begining of the table.
|
||||
entry = RtlEnumerateGenericTableAvl(table, TRUE);
|
||||
|
||||
// Advance the cursor until we reach the first entry that is greater than the key.
|
||||
while (!(ebpf_hash_map_compare(table, (uint8_t*)previous_key, entry) == GenericGreaterThan))
|
||||
{
|
||||
entry = RtlEnumerateGenericTableAvl(table, FALSE);
|
||||
if (!entry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = RtlEnumerateGenericTableAvl(table, FALSE);
|
||||
}
|
||||
}
|
||||
if (entry == NULL)
|
||||
{
|
||||
return EBPF_ERROR_NO_MORE_KEYS;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(next_key, entry, key_size);
|
||||
}
|
||||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -108,7 +108,12 @@ ebpf_error_code_t ebpf_hash_table_create(ebpf_hash_table_t** hash_table, size_t
|
|||
{
|
||||
UNREFERENCED_PARAMETER(key_size);
|
||||
UNREFERENCED_PARAMETER(value_size);
|
||||
*hash_table = reinterpret_cast<ebpf_hash_table_t *>(new hash_table_t());
|
||||
auto local_hash_table = new hash_table_t();
|
||||
local_hash_table->key_size = key_size;
|
||||
local_hash_table->value_size = value_size;
|
||||
*hash_table = reinterpret_cast<ebpf_hash_table_t *>(local_hash_table);
|
||||
|
||||
|
||||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -129,7 +134,7 @@ ebpf_error_code_t ebpf_hash_table_lookup(ebpf_hash_table_t* hash_table, const ui
|
|||
return EBPF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
std::copy(local_value->second.begin(), local_value->second.end(), *value);
|
||||
*value = local_value->second.data();
|
||||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -157,3 +162,22 @@ ebpf_error_code_t ebpf_hash_table_delete(ebpf_hash_table_t* hash_table, const ui
|
|||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
ebpf_error_code_t ebpf_hash_table_next_key(ebpf_hash_table_t* hash_table, const uint8_t* previous_key, uint8_t* next_key)
|
||||
{
|
||||
hash_table_t* local_hash_table = reinterpret_cast<decltype(local_hash_table)>(hash_table);
|
||||
auto iter = local_hash_table->hash_table.begin();
|
||||
|
||||
if (previous_key)
|
||||
{
|
||||
std::vector<uint8_t> local_key(previous_key, previous_key + local_hash_table->key_size);
|
||||
iter = local_hash_table->hash_table.upper_bound(local_key);
|
||||
}
|
||||
|
||||
if (iter == local_hash_table->hash_table.end())
|
||||
{
|
||||
return EBPF_ERROR_NO_MORE_KEYS;
|
||||
}
|
||||
std::copy(iter->first.begin(), iter->first.end(), next_key);
|
||||
|
||||
return EBPF_ERROR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ Environment:
|
|||
#include "ebpf_protocol.h"
|
||||
#include "ebpf_core.h"
|
||||
|
||||
#define RTL_OFFSET_OF(s, m) (((size_t)&((s*)0)->m))
|
||||
|
||||
// Driver global variables
|
||||
|
||||
static DEVICE_OBJECT* _wdm_device_object;
|
||||
|
@ -92,6 +94,12 @@ inline NTSTATUS ebpf_error_code_to_ntstatus(ebpf_error_code_t error)
|
|||
case EBPF_ERROR_BLOCKED_BY_POLICY:
|
||||
// TODO: Find a better erorr code for this.
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
case EBPF_ERROR_NO_MORE_KEYS:
|
||||
return STATUS_NO_MORE_MATCHES;
|
||||
case EBPF_ERROR_INVALID_HANDLE:
|
||||
return STATUS_INVALID_HANDLE;
|
||||
case EBPF_ERROR_NOT_SUPPORTED:
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
default:
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
@ -271,6 +279,7 @@ static const struct {
|
|||
{ ebpf_core_protocol_map_lookup_element, sizeof(struct _ebpf_operation_map_lookup_element_request), sizeof(struct _ebpf_operation_map_lookup_element_reply) },
|
||||
{ ebpf_core_protocol_map_update_element, sizeof(struct _ebpf_operation_map_update_element_request), 0 },
|
||||
{ ebpf_core_protocol_map_delete_element, sizeof(struct _ebpf_operation_map_delete_element_request), 0 },
|
||||
{ ebpf_core_protocol_map_get_next_key, RTL_OFFSET_OF(ebpf_operation_map_next_key_request_t, previous_key), sizeof(ebpf_operation_map_next_key_reply_t) },
|
||||
{ ebpf_core_protocol_enumerate_maps, sizeof(struct _ebpf_operation_enumerate_maps_request), sizeof(struct _ebpf_operation_enumerate_maps_reply) },
|
||||
{ ebpf_core_protocol_query_map_definition, sizeof(struct _ebpf_operation_query_map_definition_request), sizeof(struct _ebpf_operation_query_map_definition_reply) },
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace ebpf
|
|||
};
|
||||
|
||||
#include "unwind_helper.h"
|
||||
#include <WinSock2.h>
|
||||
|
||||
static const struct {
|
||||
ebpf_error_code_t(*protocol_handler)(_In_ const void* input_buffer, void* output_buffer);
|
||||
|
@ -37,6 +38,7 @@ static const struct {
|
|||
{ reinterpret_cast<ebpf_error_code_t(*)(_In_ const void* input_buffer, void* output_buffer)>(ebpf_core_protocol_map_lookup_element), sizeof(struct _ebpf_operation_map_lookup_element_request), sizeof(struct _ebpf_operation_map_lookup_element_reply) },
|
||||
{ reinterpret_cast<ebpf_error_code_t(*)(_In_ const void* input_buffer, void* output_buffer)>(ebpf_core_protocol_map_update_element), sizeof(struct _ebpf_operation_map_update_element_request), 0 },
|
||||
{ reinterpret_cast<ebpf_error_code_t(*)(_In_ const void* input_buffer, void* output_buffer)>(ebpf_core_protocol_map_delete_element), sizeof(struct _ebpf_operation_map_delete_element_request), 0 },
|
||||
{ reinterpret_cast<ebpf_error_code_t(*)(_In_ const void* input_buffer, void* output_buffer)>(ebpf_core_protocol_map_get_next_key), offsetof(ebpf_operation_map_next_key_request_t, previous_key), sizeof(ebpf_operation_map_next_key_reply_t) },
|
||||
{ reinterpret_cast<ebpf_error_code_t(*)(_In_ const void* input_buffer, void* output_buffer)>(ebpf_core_protocol_enumerate_maps), sizeof(struct _ebpf_operation_enumerate_maps_request), sizeof(struct _ebpf_operation_enumerate_maps_reply) },
|
||||
{ reinterpret_cast<ebpf_error_code_t(*)(_In_ const void* input_buffer, void* output_buffer)>(ebpf_core_protocol_query_map_definition), sizeof(struct _ebpf_operation_query_map_definition_request), sizeof(struct _ebpf_operation_query_map_definition_reply) },
|
||||
};
|
||||
|
@ -130,6 +132,9 @@ GlueDeviceIoControl(
|
|||
case EBPF_ERROR_INVALID_PARAMETER:
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
break;
|
||||
case EBPF_ERROR_NO_MORE_KEYS:
|
||||
SetLastError(ERROR_NO_MORE_ITEMS);
|
||||
break;
|
||||
default:
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
break;
|
||||
|
@ -167,6 +172,8 @@ TEST_CASE("droppacket-jit", "[droppacket_jit]")
|
|||
close_handle_handler = GlueCloseHandle;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
ebpf_handle_t map_handle;
|
||||
uint32_t count_of_map_handle = 1;
|
||||
uint32_t result = 0;
|
||||
const char* error_message = NULL;
|
||||
bool ec_initialized = false;
|
||||
|
@ -185,7 +192,7 @@ TEST_CASE("droppacket-jit", "[droppacket_jit]")
|
|||
REQUIRE(ebpf_api_initiate() == ERROR_SUCCESS);
|
||||
api_initialized = true;
|
||||
|
||||
REQUIRE(ebpf_api_load_program(SAMPLE_PATH "droppacket.o", "xdp", EBPF_EXECUTION_JIT, &program_handle, &error_message) == ERROR_SUCCESS);
|
||||
REQUIRE(ebpf_api_load_program(SAMPLE_PATH "droppacket.o", "xdp", EBPF_EXECUTION_JIT, &program_handle, &count_of_map_handle, &map_handle, &error_message) == ERROR_SUCCESS);
|
||||
|
||||
REQUIRE(ebpf_api_attach_program(program_handle, EBPF_PROGRAM_TYPE_XDP) == ERROR_SUCCESS);
|
||||
|
||||
|
@ -193,19 +200,19 @@ TEST_CASE("droppacket-jit", "[droppacket_jit]")
|
|||
|
||||
uint32_t key = 0;
|
||||
uint64_t value = 1000;
|
||||
REQUIRE(ebpf_api_map_update_element((ebpf_handle_t)1, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
REQUIRE(ebpf_api_map_update_element(map_handle, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
|
||||
// Test that we drop the packet and increment the map
|
||||
ebpf::xdp_md_t ctx{ packet.data(), packet.data() + packet.size() };
|
||||
REQUIRE(ebpf_core_invoke_hook(EBPF_PROGRAM_TYPE_XDP, &ctx, &result) == EBPF_ERROR_SUCCESS);
|
||||
REQUIRE(result == 2);
|
||||
|
||||
REQUIRE(ebpf_api_map_lookup_element((ebpf_handle_t)1, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
REQUIRE(ebpf_api_map_lookup_element(map_handle, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
REQUIRE(value == 1001);
|
||||
|
||||
REQUIRE(ebpf_api_map_delete_element((ebpf_handle_t)1, sizeof(key), (uint8_t*)&key) == ERROR_SUCCESS);
|
||||
REQUIRE(ebpf_api_map_delete_element(map_handle, sizeof(key), (uint8_t*)&key) == ERROR_SUCCESS);
|
||||
|
||||
REQUIRE(ebpf_api_map_lookup_element((ebpf_handle_t)1, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
REQUIRE(ebpf_api_map_lookup_element(map_handle, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
REQUIRE(value == 0);
|
||||
|
||||
|
||||
|
@ -215,7 +222,7 @@ TEST_CASE("droppacket-jit", "[droppacket_jit]")
|
|||
REQUIRE(ebpf_core_invoke_hook(EBPF_PROGRAM_TYPE_XDP, &ctx2, &result) == EBPF_ERROR_SUCCESS);
|
||||
REQUIRE(result == 1);
|
||||
|
||||
REQUIRE(ebpf_api_map_lookup_element((ebpf_handle_t)1, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
REQUIRE(ebpf_api_map_lookup_element(map_handle, sizeof(key), (uint8_t*)&key, sizeof(value), (uint8_t*)&value) == ERROR_SUCCESS);
|
||||
REQUIRE(value == 0);
|
||||
}
|
||||
|
||||
|
@ -229,6 +236,8 @@ TEST_CASE("droppacket-interpret", "[droppacket_interpret]")
|
|||
const char* error_message = NULL;
|
||||
bool ec_initialized = false;
|
||||
bool api_initialized = false;
|
||||
ebpf_handle_t map_handle;
|
||||
uint32_t count_of_map_handle = 1;
|
||||
_unwind_helper on_exit([&]
|
||||
{
|
||||
ebpf_api_free_error_message(error_message);
|
||||
|
@ -245,7 +254,7 @@ TEST_CASE("droppacket-interpret", "[droppacket_interpret]")
|
|||
REQUIRE(ebpf_api_initiate() == ERROR_SUCCESS);
|
||||
api_initialized = true;
|
||||
|
||||
REQUIRE(ebpf_api_load_program(SAMPLE_PATH "droppacket.o", "xdp", EBPF_EXECUTION_INTERPRET, &program_handle, &error_message) == ERROR_SUCCESS);
|
||||
REQUIRE(ebpf_api_load_program(SAMPLE_PATH "droppacket.o", "xdp", EBPF_EXECUTION_INTERPRET, &program_handle, &count_of_map_handle, &map_handle, &error_message) == ERROR_SUCCESS);
|
||||
|
||||
REQUIRE(ebpf_api_attach_program(program_handle, EBPF_PROGRAM_TYPE_XDP) == ERROR_SUCCESS);
|
||||
|
||||
|
@ -349,3 +358,121 @@ TEST_CASE("verify section", "[verify section]") {
|
|||
REQUIRE(error_message == nullptr);
|
||||
}
|
||||
|
||||
|
||||
typedef struct _process_entry
|
||||
{
|
||||
uint32_t count;
|
||||
uint8_t name[64];
|
||||
uint64_t appid_length;
|
||||
} process_entry_t;
|
||||
|
||||
|
||||
uint32_t get_bind_count_for_pid(ebpf_handle_t handle, uint64_t pid)
|
||||
{
|
||||
process_entry_t entry{};
|
||||
REQUIRE(ebpf_api_map_lookup_element(handle, sizeof(pid), (uint8_t*)&pid, sizeof(entry), (uint8_t*)&entry) == ERROR_SUCCESS);
|
||||
|
||||
return entry.count;
|
||||
}
|
||||
|
||||
ebpf::bind_action_t emulate_bind(uint64_t pid, const char * appid)
|
||||
{
|
||||
uint32_t result;
|
||||
std::string app_id = appid;
|
||||
ebpf::bind_md_t ctx{0};
|
||||
ctx.app_id_start = const_cast<char*>(app_id.c_str());
|
||||
ctx.app_id_end = const_cast<char*>(app_id.c_str()) + app_id.size();
|
||||
ctx.process_id = pid;
|
||||
ctx.operation = ebpf::BIND_OPERATION_BIND;
|
||||
REQUIRE(ebpf_core_invoke_hook(EBPF_PROGRAM_TYPE_BIND, &ctx, &result) == EBPF_ERROR_SUCCESS);
|
||||
return static_cast<ebpf::bind_action_t>(result);
|
||||
}
|
||||
|
||||
void emulate_unbind(uint64_t pid, const char* appid)
|
||||
{
|
||||
uint32_t result;
|
||||
std::string app_id = appid;
|
||||
ebpf::bind_md_t ctx{ 0 };
|
||||
ctx.process_id = pid;
|
||||
ctx.operation = ebpf::BIND_OPERATION_UNBIND;
|
||||
REQUIRE(ebpf_core_invoke_hook(EBPF_PROGRAM_TYPE_BIND, &ctx, &result) == EBPF_ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
void set_bind_limit(ebpf_handle_t handle, uint32_t limit)
|
||||
{
|
||||
uint32_t limit_key = 0;
|
||||
REQUIRE(ebpf_api_map_update_element(handle, sizeof(limit_key), (uint8_t*)&limit_key, sizeof(limit), (uint8_t*)&limit) == ERROR_SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("bindmonitor-interpret", "[bindmonitor_interpret]")
|
||||
{
|
||||
device_io_control_handler = GlueDeviceIoControl;
|
||||
create_file_handler = GlueCreateFileW;
|
||||
close_handle_handler = GlueCloseHandle;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
const char* error_message = NULL;
|
||||
bool ec_initialized = false;
|
||||
bool api_initialized = false;
|
||||
ebpf_handle_t map_handles[2];
|
||||
uint32_t count_of_map_handles = 2;
|
||||
uint64_t fake_pid = 12345;
|
||||
|
||||
_unwind_helper on_exit([&] {
|
||||
ebpf_api_free_error_message(error_message);
|
||||
if (api_initialized)
|
||||
ebpf_api_terminate();
|
||||
if (ec_initialized)
|
||||
ebpf_core_terminate();
|
||||
});
|
||||
|
||||
REQUIRE(ebpf_core_initialize() == EBPF_ERROR_SUCCESS);
|
||||
ec_initialized = true;
|
||||
|
||||
REQUIRE(ebpf_api_initiate() == ERROR_SUCCESS);
|
||||
api_initialized = true;
|
||||
|
||||
REQUIRE(ebpf_api_load_program(SAMPLE_PATH "bindmonitor.o", "bind", EBPF_EXECUTION_INTERPRET, &program_handle, &count_of_map_handles, map_handles, &error_message) == ERROR_SUCCESS);
|
||||
REQUIRE(error_message == NULL);
|
||||
|
||||
REQUIRE(ebpf_api_attach_program(program_handle, EBPF_PROGRAM_TYPE_BIND) == ERROR_SUCCESS);
|
||||
|
||||
// Apply policy of maximum 2 binds per process
|
||||
set_bind_limit(map_handles[1], 2);
|
||||
|
||||
// Bind first port - success
|
||||
REQUIRE(emulate_bind(fake_pid, "fake_app_1") == ebpf::BIND_PERMIT);
|
||||
REQUIRE(get_bind_count_for_pid(map_handles[0], fake_pid) == 1);
|
||||
|
||||
// Bind second port - success
|
||||
REQUIRE(emulate_bind(fake_pid, "fake_app_1") == ebpf::BIND_PERMIT);
|
||||
REQUIRE(get_bind_count_for_pid(map_handles[0], fake_pid) == 2);
|
||||
|
||||
// Bind third port - blocked
|
||||
REQUIRE(emulate_bind(fake_pid, "fake_app_1") == ebpf::BIND_DENY);
|
||||
REQUIRE(get_bind_count_for_pid(map_handles[0], fake_pid) == 2);
|
||||
|
||||
// Unbind second port
|
||||
emulate_unbind(fake_pid, "fake_app_1");
|
||||
REQUIRE(get_bind_count_for_pid(map_handles[0], fake_pid) == 1);
|
||||
|
||||
// Unbind first port
|
||||
emulate_unbind(fake_pid, "fake_app_1");
|
||||
REQUIRE(get_bind_count_for_pid(map_handles[0], fake_pid) == 0);
|
||||
|
||||
// Unbind a port we don't own
|
||||
emulate_unbind(fake_pid, "fake_app_1");
|
||||
REQUIRE(get_bind_count_for_pid(map_handles[0], fake_pid) == 0);
|
||||
|
||||
fake_pid = 54321;
|
||||
REQUIRE(emulate_bind(fake_pid, "fake_app_2") == ebpf::BIND_PERMIT);
|
||||
REQUIRE(get_bind_count_for_pid(map_handles[0], fake_pid) == 1);
|
||||
|
||||
uint64_t pid;
|
||||
REQUIRE(ebpf_api_map_next_key(map_handles[0], sizeof(uint64_t), NULL, reinterpret_cast<uint8_t*>(&pid)) == ERROR_SUCCESS);
|
||||
REQUIRE(pid != 0);
|
||||
REQUIRE(ebpf_api_map_next_key(map_handles[0], sizeof(uint64_t), reinterpret_cast<uint8_t*>(&pid), reinterpret_cast<uint8_t*>(&pid)) == ERROR_SUCCESS);
|
||||
REQUIRE(pid != 0);
|
||||
REQUIRE(ebpf_api_map_next_key(map_handles[0], sizeof(uint64_t), reinterpret_cast<uint8_t*>(&pid), reinterpret_cast<uint8_t*>(&pid)) == ERROR_NO_MORE_ITEMS);
|
||||
}
|
|
@ -11,35 +11,78 @@
|
|||
|
||||
#include "ebpf.h"
|
||||
|
||||
typedef struct _process_entry
|
||||
{
|
||||
uint32_t count;
|
||||
uint8_t name[64];
|
||||
} process_entry_t;
|
||||
|
||||
#pragma clang section data="maps"
|
||||
bpf_map_def_t process_map = {
|
||||
.size = sizeof(bpf_map_def_t),
|
||||
.type = EBPF_MAP_TYPE_HASH,
|
||||
.key_size = sizeof(__u64),
|
||||
.value_size = sizeof(__u32),
|
||||
.key_size = sizeof(uint64_t),
|
||||
.value_size = sizeof(process_entry_t),
|
||||
.max_entries = 1024
|
||||
};
|
||||
|
||||
bpf_map_def_t limits_map = {
|
||||
.size = sizeof(bpf_map_def_t),
|
||||
.type = EBPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(uint32_t),
|
||||
.value_size = sizeof(uint32_t),
|
||||
.max_entries = 1
|
||||
};
|
||||
|
||||
inline void copy_app_id(process_entry_t* entry, uint64_t start_index, char* begin, char* end)
|
||||
{
|
||||
uint64_t index = 0;
|
||||
for (index = start_index; index < start_index + 16; index++)
|
||||
{
|
||||
entry->name[index] = (begin + index < end) ? begin[index] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang section text="bind"
|
||||
int BindMonitor(bind_md_t* ctx)
|
||||
{
|
||||
long key = ctx->process_id;
|
||||
__u32* count = ebpf_map_lookup_elem(&process_map, &key);
|
||||
|
||||
if (!count)
|
||||
uint64_t key = ctx->process_id;
|
||||
uint32_t limit_key = 0;
|
||||
uint32_t* limit = ebpf_map_lookup_elem(&limits_map, &limit_key);
|
||||
if (!limit || *limit == 0)
|
||||
{
|
||||
long value = 0;
|
||||
ebpf_map_update_element(&process_map, &value, &key, 0);
|
||||
count = ebpf_map_lookup_elem(&process_map, &key);
|
||||
return BIND_PERMIT;
|
||||
}
|
||||
|
||||
process_entry_t* entry = ebpf_map_lookup_elem(&process_map, &key);
|
||||
if (!entry)
|
||||
{
|
||||
process_entry_t value = { 0 };
|
||||
// To work around a limitation in eBPF verifier, copy the string
|
||||
// in blocks of 16 bytes. Copying all 64 bytes triggers a verification
|
||||
// failure.
|
||||
copy_app_id(&value, 0, ctx->app_id_start, ctx->app_id_end);
|
||||
copy_app_id(&value, 16, ctx->app_id_start, ctx->app_id_end);
|
||||
copy_app_id(&value, 32, ctx->app_id_start, ctx->app_id_end);
|
||||
copy_app_id(&value, 48, ctx->app_id_start, ctx->app_id_end);
|
||||
ebpf_map_update_element(&process_map, &key, &value, 0);
|
||||
entry = ebpf_map_lookup_elem(&process_map, &key);
|
||||
}
|
||||
|
||||
if (count)
|
||||
switch (ctx->operation)
|
||||
{
|
||||
case BIND_OPERATION_BIND:
|
||||
*count = (*count) + 1;
|
||||
if (entry->count >= *limit)
|
||||
{
|
||||
return BIND_DENY;
|
||||
}
|
||||
|
||||
entry->count++;
|
||||
break;
|
||||
case BIND_OPERATION_UNBIND:
|
||||
*count = (*count) - 1;
|
||||
if (entry->count > 0)
|
||||
entry->count--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
bpf_map_def_t port_map = {
|
||||
.size = sizeof(bpf_map_def_t),
|
||||
.type = EBPF_MAP_TYPE_ARRAY,
|
||||
.key_size = sizeof(__u32),
|
||||
.value_size = sizeof(__u64),
|
||||
.key_size = sizeof(uint32_t),
|
||||
.value_size = sizeof(uint64_t),
|
||||
.max_entries = 1
|
||||
};
|
||||
|
||||
|
|
|
@ -3,12 +3,17 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
typedef unsigned long __u64;
|
||||
typedef unsigned int __u32;
|
||||
typedef unsigned short __u16;
|
||||
typedef unsigned char __u8;
|
||||
#if defined(_MSC_VER)
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
typedef unsigned long uint64_t;
|
||||
#endif
|
||||
|
||||
__u16 ntohs(__u16 us)
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
uint16_t ntohs(uint16_t us)
|
||||
{
|
||||
return us << 8 | us >> 8;
|
||||
}
|
||||
|
@ -17,17 +22,17 @@ typedef struct _xdp_md
|
|||
{
|
||||
void* data;
|
||||
void* data_end;
|
||||
__u64 data_meta;
|
||||
uint64_t data_meta;
|
||||
} xdp_md_t;
|
||||
|
||||
typedef struct _bind_md {
|
||||
void* app_id_start; // 0,8
|
||||
void* app_id_end; // 8,8
|
||||
__u64 process_id; // 16,8
|
||||
__u8 socket_address[16]; // 24,16
|
||||
__u8 socket_address_length; // 40,1
|
||||
__u8 operation; // 41,1
|
||||
__u8 protocol; // 42,1
|
||||
char* app_id_start;
|
||||
char* app_id_end;
|
||||
uint64_t process_id;
|
||||
uint8_t socket_address[16];
|
||||
uint8_t socket_address_length;
|
||||
uint8_t operation;
|
||||
uint8_t protocol;
|
||||
} bind_md_t;
|
||||
|
||||
typedef enum _bind_operation
|
||||
|
@ -46,51 +51,51 @@ typedef enum _bind_action
|
|||
|
||||
typedef struct _IPV4_HEADER {
|
||||
union {
|
||||
__u8 VersionAndHeaderLength; // Version and header length.
|
||||
uint8_t VersionAndHeaderLength; // Version and header length.
|
||||
struct {
|
||||
__u8 HeaderLength : 4;
|
||||
__u8 Version : 4;
|
||||
uint8_t HeaderLength : 4;
|
||||
uint8_t Version : 4;
|
||||
};
|
||||
};
|
||||
union {
|
||||
__u8 TypeOfServiceAndEcnField; // Type of service & ECN (RFC 3168).
|
||||
uint8_t TypeOfServiceAndEcnField; // Type of service & ECN (RFC 3168).
|
||||
struct {
|
||||
__u8 EcnField : 2;
|
||||
__u8 TypeOfService : 6;
|
||||
uint8_t EcnField : 2;
|
||||
uint8_t TypeOfService : 6;
|
||||
};
|
||||
};
|
||||
__u16 TotalLength; // Total length of datagram.
|
||||
__u16 Identification;
|
||||
uint16_t TotalLength; // Total length of datagram.
|
||||
uint16_t Identification;
|
||||
union {
|
||||
__u16 FlagsAndOffset; // Flags and fragment offset.
|
||||
uint16_t FlagsAndOffset; // Flags and fragment offset.
|
||||
struct {
|
||||
__u16 DontUse1 : 5; // High bits of fragment offset.
|
||||
__u16 MoreFragments : 1;
|
||||
__u16 DontFragment : 1;
|
||||
__u16 Reserved : 1;
|
||||
__u16 DontUse2 : 8; // Low bits of fragment offset.
|
||||
uint16_t DontUse1 : 5; // High bits of fragment offset.
|
||||
uint16_t MoreFragments : 1;
|
||||
uint16_t DontFragment : 1;
|
||||
uint16_t Reserved : 1;
|
||||
uint16_t DontUse2 : 8; // Low bits of fragment offset.
|
||||
};
|
||||
};
|
||||
__u8 TimeToLive;
|
||||
__u8 Protocol;
|
||||
__u16 HeaderChecksum;
|
||||
__u32 SourceAddress;
|
||||
__u32 DestinationAddress;
|
||||
uint8_t TimeToLive;
|
||||
uint8_t Protocol;
|
||||
uint16_t HeaderChecksum;
|
||||
uint32_t SourceAddress;
|
||||
uint32_t DestinationAddress;
|
||||
} IPV4_HEADER, *PIPV4_HEADER;
|
||||
|
||||
typedef struct UDP_HEADER_ {
|
||||
__u16 srcPort;
|
||||
__u16 destPort;
|
||||
__u16 length;
|
||||
__u16 checksum;
|
||||
uint16_t srcPort;
|
||||
uint16_t destPort;
|
||||
uint16_t length;
|
||||
uint16_t checksum;
|
||||
} UDP_HEADER;
|
||||
|
||||
typedef struct _bpf_map_def {
|
||||
__u32 size;
|
||||
__u32 type;
|
||||
__u32 key_size;
|
||||
__u32 value_size;
|
||||
__u32 max_entries;
|
||||
uint32_t size;
|
||||
uint32_t type;
|
||||
uint32_t key_size;
|
||||
uint32_t value_size;
|
||||
uint32_t max_entries;
|
||||
} bpf_map_def_t;
|
||||
|
||||
typedef enum _ebpf_map_type {
|
||||
|
@ -102,5 +107,5 @@ typedef enum _ebpf_map_type {
|
|||
typedef void* (*ebpf_map_lookup_elem_t)(void * map, void* key);
|
||||
#define ebpf_map_lookup_elem ((ebpf_map_lookup_elem_t)1)
|
||||
|
||||
typedef void (*ebpf_map_update_element_t)(void* map, void* key, void* data, __u64 flags);
|
||||
typedef void (*ebpf_map_update_element_t)(void* map, void* key, void* data, uint64_t flags);
|
||||
#define ebpf_map_update_element ((ebpf_map_update_element_t)2)
|
||||
|
|
|
@ -90,6 +90,8 @@
|
|||
<FileType>CppCode</FileType>
|
||||
<Command>clang -target bpf -O2 -Wall -c %(Filename).c -o %(Filename).o</Command>
|
||||
<Outputs>%(Filename).o;%(Outputs)</Outputs>
|
||||
<TreatOutputAsContent Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</TreatOutputAsContent>
|
||||
<TreatOutputAsContent Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</TreatOutputAsContent>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="bpf.c">
|
||||
<FileType>CppCode</FileType>
|
||||
|
|
|
@ -14,23 +14,23 @@
|
|||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bindmonitor.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bpf.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="bpf_call.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="droppacket.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ebpf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="bindmonitor.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="bpf.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="bpf_call.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="droppacket.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -11,7 +11,8 @@
|
|||
#include "api.h"
|
||||
#include <iostream>
|
||||
|
||||
static HANDLE _program_handle = INVALID_HANDLE_VALUE;
|
||||
static ebpf_handle_t _program_handle = INVALID_HANDLE_VALUE;
|
||||
static ebpf_handle_t _map_handles[10];
|
||||
|
||||
typedef enum {
|
||||
PINNED_ANY = 0,
|
||||
|
@ -134,8 +135,8 @@ unsigned long handle_ebpf_add_program(
|
|||
}
|
||||
|
||||
const char* error_message = nullptr;
|
||||
|
||||
status = ebpf_api_load_program(filename.c_str(), section.c_str(), execution, &_program_handle, &error_message);
|
||||
uint32_t count_of_map_handles = sizeof(_map_handles);
|
||||
status = ebpf_api_load_program(filename.c_str(), section.c_str(), execution, &_program_handle, &count_of_map_handles, _map_handles, &error_message);
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
if (error_message != nullptr) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче