Skip to content

Commit

Permalink
Add support for program loading flags.
Browse files Browse the repository at this point in the history
Signed-off-by: Alan Jowett <[email protected]>
  • Loading branch information
Alan Jowett committed Aug 9, 2024
1 parent f08ee5f commit 10dec46
Show file tree
Hide file tree
Showing 16 changed files with 252 additions and 9 deletions.
6 changes: 6 additions & 0 deletions docs/eBpfExtensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@ ebpf_extension_data_t* extension_data = (ebpf_extension_data_t*)ClientRegistrati
attach_parameter = extension_data->data;
```

### `ebpf_extension_data_t` Struct
This structure contains the additional data passed from the application to the attach provider. It contains the following fields:
* `data` Attach type specific data. See documentation for the attach type provider for the format of this data.
* `data_size` The length of the attach type specific data.
* `prog_attach_flags` A collection of attach type specific flags passed from the application to the attach provider.

The per-client data structure should be returned as the `ProviderBindingContext` output parameter.

Upon
Expand Down
2 changes: 2 additions & 0 deletions ebpfapi/Source.def
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ EXPORTS
bpf_program__attach_xdp
bpf_program__autoload
bpf_program__fd
bpf_program__flags
bpf_program__get_expected_attach_type
bpf_program__get_type=bpf_program__type
bpf_program__insn_cnt
Expand All @@ -90,6 +91,7 @@ EXPORTS
bpf_program__section_name
bpf_program__set_autoload
bpf_program__set_expected_attach_type
bpf_program__set_flags
bpf_program__set_type
bpf_program__type
bpf_program__unload
Expand Down
25 changes: 25 additions & 0 deletions include/bpf/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,31 @@ void
ring_buffer__free(struct ring_buffer* rb);
/** @} */

/**
* @brief Query the BPF program flags.
*
* @param[in] prog A pointer to the BPF program.
* @return The flags of the BPF program.
*/
uint64_t
bpf_program__flags(const struct bpf_program* prog);

/**
* @brief Set the BPF program flags.
* The set of flags is defined by the program type. Neither libbpf nor the eBPF runtime check the flags and only
* the extension that handles this program type will interpret them. See the documentation for the
* program type for what flags are defined for that program type.
*
* @param[in] prog A pointer to the BPF program.
* @param[in] flags The flags to set.
*
* @retval 0 The operation was successful.
* @retval <0 An error occurred, and errno was set.
*
*/
int
bpf_program__set_flags(struct bpf_program* prog, uint64_t flags);

#else
#pragma warning(push)
#pragma warning(disable : 4200) // Zero-sized array in struct/union
Expand Down
2 changes: 2 additions & 0 deletions include/ebpf_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ typedef struct _ebpf_extension_data
{
ebpf_extension_header_t header;
const void* data;
size_t data_size;
uint64_t prog_attach_flags;
} ebpf_extension_data_t;

typedef struct _ebpf_attach_provider_data
Expand Down
8 changes: 8 additions & 0 deletions include/ebpf_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ typedef enum _ebpf_helper_function
#define EBPF_ATTACH_CLIENT_DATA_CURRENT_VERSION 1
#define EBPF_PROGRAM_INFORMATION_CLIENT_DATA_CURRENT_VERSION 1

#define EBPF_ATTACH_CLIENT_DATA_VERSION_SIZE EBPF_SIZE_INCLUDING_FIELD(ebpf_extension_data_t, prog_attach_flags)
#define EBPF_ATTACH_CLIENT_DATA_VERSION_TOTAL_SIZE sizeof(ebpf_extension_data_t)
#define EBPF_ATTACH_CLIENT_DATA_HEADER_VERSION \
{ \
EBPF_ATTACH_CLIENT_DATA_CURRENT_VERSION, EBPF_ATTACH_CLIENT_DATA_VERSION_SIZE, \
EBPF_ATTACH_CLIENT_DATA_VERSION_TOTAL_SIZE \
}

// Version 1 of the eBPF extension data structures and their lengths.
#define EBPF_ATTACH_PROVIDER_DATA_CURRENT_VERSION 1
#define EBPF_ATTACH_PROVIDER_DATA_CURRENT_VERSION_SIZE EBPF_SIZE_INCLUDING_FIELD(ebpf_attach_provider_data_t, link_type)
Expand Down
13 changes: 13 additions & 0 deletions libs/api/api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef struct bpf_program
bool pinned;
const char* log_buffer;
uint32_t log_buffer_size;
uint64_t flags;
} ebpf_program_t;

typedef struct bpf_map
Expand Down Expand Up @@ -759,3 +760,15 @@ ebpf_api_thread_local_cleanup() noexcept;
*/
void
ebpf_api_thread_local_initialize() noexcept;

/**
* @brief Set the flags on a program
*
* @param[in] program_fd File descriptor for the program.
* @param[in] flags Flags to set on the program.
*
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_ARGUMENT One or more parameters are wrong.
*/
_Must_inspect_result_ ebpf_result_t
ebpf_program_set_flags(fd_t program_fd, uint64_t flags) noexcept;
30 changes: 30 additions & 0 deletions libs/api/ebpf_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2131,6 +2131,12 @@ _initialize_ebpf_programs_native(
result = EBPF_NO_MEMORY;
goto Exit;
}
if (program->flags != 0) {
result = ebpf_program_set_flags(program->fd, program->flags);
if (result != EBPF_SUCCESS) {
goto Exit;
}
}
program->handle = program_handles[i];
program_handles[i] = ebpf_handle_invalid;
program->program_type = info.type_uuid;
Expand Down Expand Up @@ -3293,6 +3299,13 @@ _Requires_lock_not_held_(_ebpf_state_mutex) static ebpf_result_t

program->fd = _create_file_descriptor_for_handle(program->handle);

if (program->flags != 0) {
result = ebpf_program_set_flags(program->fd, program->flags);
if (result != EBPF_SUCCESS) {
break;
}
}

// Populate load_info.
ebpf_program_load_info load_info = {0};
load_info.object_name = const_cast<char*>(object->object_name);
Expand Down Expand Up @@ -4673,3 +4686,20 @@ ebpf_api_thread_local_initialize() noexcept
// Nothing to do.
// Added for symmetry with ebpf_api_thread_local_cleanup.
}

_Must_inspect_result_ ebpf_result_t
ebpf_program_set_flags(fd_t program_fd, uint64_t flags) noexcept
{
ebpf_handle_t program_handle = _get_handle_from_file_descriptor(program_fd);
if (program_handle == ebpf_handle_invalid) {
return EBPF_INVALID_FD;
}

ebpf_operation_program_set_flags_request_t request;
request.header.id = ebpf_operation_id_t::EBPF_OPERATION_PROGRAM_SET_FLAGS;
request.header.length = sizeof(request);
request.program_handle = program_handle;
request.flags = flags;

return win32_error_code_to_ebpf_result(invoke_ioctl(request));
}
16 changes: 16 additions & 0 deletions libs/api/libbpf_program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,3 +755,19 @@ bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts* opts)

return 0;
}

uint64_t
bpf_program__flags(const struct bpf_program* prog)
{
return static_cast<uint32_t>(prog->flags);
}

int
bpf_program__set_flags(struct bpf_program* prog, uint64_t flags)
{
if (prog->object->loaded) {
return libbpf_err(-EBUSY);
}
prog->flags = flags;
return 0;
}
25 changes: 25 additions & 0 deletions libs/execution_context/ebpf_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2114,6 +2114,30 @@ _ebpf_core_protocol_ring_buffer_map_write_data(_In_ const ebpf_operation_ring_bu
EBPF_RETURN_RESULT(result);
}

static ebpf_result_t
_ebpf_core_protocol_program_set_flags(_In_ const ebpf_operation_program_set_flags_request_t* request)
{
EBPF_LOG_ENTRY();

ebpf_program_t* program = NULL;

ebpf_result_t result =
EBPF_OBJECT_REFERENCE_BY_HANDLE(request->program_handle, EBPF_OBJECT_PROGRAM, (ebpf_core_object_t**)&program);

if (result != EBPF_SUCCESS) {
goto Exit;
}

ebpf_program_set_flags(program, request->flags);

Exit:
if (program) {
EBPF_OBJECT_RELEASE_REFERENCE((ebpf_core_object_t*)program);
}

EBPF_RETURN_RESULT(result);
}

static void*
_ebpf_core_map_find_element(ebpf_map_t* map, const uint8_t* key)
{
Expand Down Expand Up @@ -2655,6 +2679,7 @@ static ebpf_protocol_handler_t _ebpf_protocol_handlers[] = {
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_FIXED_REPLY(map_delete_element_batch, keys, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_VARIABLE_REPLY(
map_get_next_key_value_batch, previous_key, data, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_NO_REPLY(program_set_flags, PROTOCOL_ALL_MODES),
};

_Must_inspect_result_ ebpf_result_t
Expand Down
14 changes: 9 additions & 5 deletions libs/execution_context/ebpf_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ _ebpf_link_client_detach_provider(void* client_binding_context)
}

static void
_ebpf_link_free(_Frees_ptr_ ebpf_core_object_t* object)
_ebpf_link_free(_In_ _Frees_ptr_ ebpf_core_object_t* object)
{
ebpf_link_t* link = (ebpf_link_t*)object;
ebpf_free((void*)link->client_data.data);
Expand Down Expand Up @@ -290,7 +290,9 @@ ebpf_link_create(
ebpf_lock_state_t state = ebpf_lock_lock(&local_link->lock);
lock_held = true;

local_link->client_data.header.size = context_data_length;
ebpf_extension_header_t header = EBPF_ATTACH_CLIENT_DATA_HEADER_VERSION;

local_link->client_data.header = header;

if (context_data_length > 0) {
local_link->client_data.data = ebpf_allocate_with_tag(context_data_length, EBPF_POOL_TAG_LINK);
Expand All @@ -299,6 +301,7 @@ ebpf_link_create(
goto Exit;
}
memcpy((void*)local_link->client_data.data, context_data, context_data_length);
local_link->client_data.data_size = context_data_length;
}

local_link->module_id.Guid = module_id;
Expand Down Expand Up @@ -365,6 +368,7 @@ ebpf_link_attach_program(_Inout_ ebpf_link_t* link, _Inout_ ebpf_program_t* prog

link->program = program;
link->program_type = ebpf_program_type_uuid(link->program);
link->client_data.prog_attach_flags = ebpf_program_get_flags(link->program);

// Attach the program to the link.
ebpf_program_attach_link(program, link);
Expand Down Expand Up @@ -660,10 +664,10 @@ ebpf_link_get_info(

// Copy any additional parameters.
size_t size = sizeof(struct bpf_link_info) - FIELD_OFFSET(struct bpf_link_info, attach_data);
if ((link->client_data.header.size > 0) && (link->client_data.header.size <= size)) {
memcpy(&info->attach_data, link->client_data.data, link->client_data.header.size);
}

if ((link->client_data.data_size > 0) && (link->client_data.data_size <= size)) {
memcpy(&info->attach_data, link->client_data.data, link->client_data.data_size);
}
ebpf_lock_unlock((ebpf_lock_t*)&link->lock, state);

*info_size = sizeof(*info);
Expand Down
15 changes: 14 additions & 1 deletion libs/execution_context/ebpf_program.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ typedef struct _ebpf_program
size_t helper_function_count;
uint32_t* helper_function_ids;
bool helper_ids_set;
uint64_t flags;

// Lock protecting the fields below.
ebpf_lock_t lock;
Expand Down Expand Up @@ -2663,4 +2664,16 @@ ebpf_program_get_runtime_state(_In_ const void* program_context, _Outptr_ const
// slot [0] contains the execution context state.
ebpf_context_header_t* header = CONTAINING_RECORD(program_context, ebpf_context_header_t, context);
*state = (ebpf_execution_context_state_t*)header->context_header[0];
}
}

uint64_t
ebpf_program_get_flags(_In_ const ebpf_program_t* program)
{
return program->flags;
}

void
ebpf_program_set_flags(_Inout_ ebpf_program_t* program, uint64_t flags)
{
program->flags = flags;
}
18 changes: 18 additions & 0 deletions libs/execution_context/ebpf_program.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,24 @@ extern "C"
ebpf_program_get_runtime_state(
_In_ const void* program_context, _Outptr_ const ebpf_execution_context_state_t** state);

/**
* @brief Query the flags set on the program.
*
* @param[in] program The program to query.
* @return The flags set on the program.
*/
uint64_t
ebpf_program_get_flags(_In_ const ebpf_program_t* program);

/**
* @brief Set the flags on the program.
*
* @param[in] program The program to set the flags on.
* @param[in] flags The flags to set on the program.
*/
void
ebpf_program_set_flags(_Inout_ ebpf_program_t* program, uint64_t flags);

#ifdef __cplusplus
}
#endif
8 changes: 8 additions & 0 deletions libs/execution_context/ebpf_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ typedef enum _ebpf_operation_id
EBPF_OPERATION_MAP_UPDATE_ELEMENT_BATCH,
EBPF_OPERATION_MAP_DELETE_ELEMENT_BATCH,
EBPF_OPERATION_MAP_GET_NEXT_KEY_VALUE_BATCH,
EBPF_OPERATION_PROGRAM_SET_FLAGS,
} ebpf_operation_id_t;

typedef enum _ebpf_code_type
Expand Down Expand Up @@ -524,3 +525,10 @@ typedef struct _ebpf_operation_map_get_next_key_value_batch_reply
// Data is a concatenation of key+value.
uint8_t data[1];
} ebpf_operation_map_get_next_key_value_batch_reply_t;

typedef struct _ebpf_operation_program_set_flags_request
{
struct _ebpf_operation_header header;
ebpf_handle_t program_handle;
uint64_t flags;
} ebpf_operation_program_set_flags_request_t;
5 changes: 2 additions & 3 deletions libs/shared/shared_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ uint16_t _supported_ebpf_extension_version[] = {
EBPF_PROGRAM_SECTION_INFORMATION_CURRENT_VERSION,
};

#define EBPF_ATTACH_PROVIDER_DATA_SIZE_0 \
EBPF_OFFSET_OF(ebpf_attach_provider_data_t, link_type) + sizeof(enum bpf_link_type)
size_t _ebpf_attach_provider_data_supported_size[] = {EBPF_ATTACH_PROVIDER_DATA_SIZE_0};
#define EBPF_ATTACH_PROVIDER_DATA_SIZE_1 EBPF_SIZE_INCLUDING_FIELD(ebpf_attach_provider_data_t, link_type)
size_t _ebpf_attach_provider_data_supported_size[] = {EBPF_ATTACH_PROVIDER_DATA_SIZE_1};

#define EBPF_PROGRAM_TYPE_DESCRIPTOR_SIZE_0 EBPF_OFFSET_OF(ebpf_program_type_descriptor_t, is_privileged) + sizeof(char)
size_t _ebpf_program_type_descriptor_supported_size[] = {EBPF_PROGRAM_TYPE_DESCRIPTOR_SIZE_0};
Expand Down
9 changes: 9 additions & 0 deletions tests/end_to_end/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "ebpf_nethooks.h"
#include "ebpf_platform.h"
#include "ebpf_program_types.h"
#include "ebpf_windows.h"
#include "net_ebpf_ext_program_info.h"
#include "sample_ext_program_info.h"
#include "usersim/ke.h"
Expand Down Expand Up @@ -279,6 +280,12 @@ typedef class _single_instance_hook : public _hook_helper
return batch_end_function(state);
}

const ebpf_extension_data_t*
get_client_data() const
{
return client_data;
}

private:
static NTSTATUS
provider_attach_client_callback(
Expand All @@ -301,6 +308,8 @@ typedef class _single_instance_hook : public _hook_helper
hook->client_binding_context = client_binding_context;
hook->nmr_binding_handle = nmr_binding_handle;
hook->client_dispatch_table = (ebpf_extension_dispatch_table_t*)client_dispatch;
hook->client_data =
reinterpret_cast<const ebpf_extension_data_t*>(client_registration_instance->NpiSpecificCharacteristics);
*provider_binding_context = provider_context;
*provider_dispatch = NULL;
return STATUS_SUCCESS;
Expand Down
Loading

0 comments on commit 10dec46

Please sign in to comment.