Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified tests/libfuzzer/netebpfext_fuzzer/corpus/bind
Binary file not shown.
Binary file modified tests/libfuzzer/netebpfext_fuzzer/corpus/cgroup_sock_addr
Binary file not shown.
Binary file modified tests/libfuzzer/netebpfext_fuzzer/corpus/sock_ops
Binary file not shown.
Binary file modified tests/libfuzzer/netebpfext_fuzzer/corpus/xdp
Binary file not shown.
9 changes: 7 additions & 2 deletions tests/libfuzzer/netebpfext_fuzzer/libfuzz_harness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef struct
uint8_t ctx_offset;
uint8_t ctx_length;
uint32_t return_value;
uint32_t program_result;
} netebpfext_fuzzer_metadata_t;

typedef struct _test_client_context
Expand Down Expand Up @@ -62,7 +63,7 @@ netebpfext_unit_invoke_program(
}

*result = client_context->metadata.return_value;
return EBPF_SUCCESS;
return (ebpf_result_t)client_context->metadata.program_result;
}

FUZZ_EXPORT int __cdecl LLVMFuzzerInitialize(int*, char***) { return 0; }
Expand Down Expand Up @@ -103,7 +104,9 @@ FUZZ_EXPORT int __cdecl LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
BPF_CGROUP_INET4_CONNECT_AUTHORIZATION,
BPF_CGROUP_INET6_CONNECT_AUTHORIZATION,
BPF_CGROUP_INET4_BIND,
BPF_CGROUP_INET6_BIND};
BPF_CGROUP_INET6_BIND,
BPF_CGROUP_INET4_LISTEN,
BPF_CGROUP_INET6_LISTEN};
break;
case BPF_PROG_TYPE_SOCK_OPS:
client_context.base.desired_attach_types = {BPF_CGROUP_SOCK_OPS};
Expand Down Expand Up @@ -149,6 +152,8 @@ FUZZ_EXPORT int __cdecl LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
(void)helper.test_cgroup_inet6_connect(&parameters);
(void)helper.test_cgroup_inet4_connect_authorization(&parameters);
(void)helper.test_cgroup_inet6_connect_authorization(&parameters);
(void)helper.test_cgroup_inet4_listen(&parameters);
Comment thread
mikeagun marked this conversation as resolved.
(void)helper.test_cgroup_inet6_listen(&parameters);
Comment thread
mikeagun marked this conversation as resolved.
break;
case BPF_PROG_TYPE_SOCK_OPS:
(void)helper.test_sock_ops_v4(&parameters, nullptr);
Expand Down
49 changes: 32 additions & 17 deletions tests/netebpfext_unit/netebpf_ext_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,56 +49,59 @@ typedef class _netebpf_ext_helper
get_program_info_provider_data(_In_ const GUID& program_info_provider);

FWP_ACTION_TYPE
test_bind_ipv4(_In_ fwp_classify_parameters_t* parameters) { return usersim_fwp_bind_ipv4(parameters); }
test_bind_ipv4(_In_ const fwp_classify_parameters_t* parameters)
{
return usersim_fwp_bind_ipv4(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_cgroup_inet4_recv_accept(_In_ fwp_classify_parameters_t* parameters)
test_cgroup_inet4_recv_accept(_In_ const fwp_classify_parameters_t* parameters)
{
return usersim_fwp_cgroup_inet4_recv_accept(parameters);
return usersim_fwp_cgroup_inet4_recv_accept(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_cgroup_inet6_recv_accept(_In_ fwp_classify_parameters_t* parameters)
test_cgroup_inet6_recv_accept(_In_ const fwp_classify_parameters_t* parameters)
{
return usersim_fwp_cgroup_inet6_recv_accept(parameters);
return usersim_fwp_cgroup_inet6_recv_accept(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_cgroup_inet4_connect(_In_ fwp_classify_parameters_t* parameters)
test_cgroup_inet4_connect(_In_ const fwp_classify_parameters_t* parameters)
{
return usersim_fwp_cgroup_inet4_connect(parameters);
return usersim_fwp_cgroup_inet4_connect(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_cgroup_inet6_connect(_In_ fwp_classify_parameters_t* parameters)
test_cgroup_inet6_connect(_In_ const fwp_classify_parameters_t* parameters)
{
return usersim_fwp_cgroup_inet6_connect(parameters);
return usersim_fwp_cgroup_inet6_connect(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_cgroup_inet4_connect_authorization(_In_ fwp_classify_parameters_t* parameters)
test_cgroup_inet4_connect_authorization(_In_ const fwp_classify_parameters_t* parameters)
{
// CONNECT_AUTHORIZATION uses the same underlying simulation as regular CONNECT.
return usersim_fwp_cgroup_inet4_connect(parameters);
return usersim_fwp_cgroup_inet4_connect(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_cgroup_inet6_connect_authorization(_In_ fwp_classify_parameters_t* parameters)
test_cgroup_inet6_connect_authorization(_In_ const fwp_classify_parameters_t* parameters)
{
// CONNECT_AUTHORIZATION uses the same underlying simulation as regular CONNECT.
return usersim_fwp_cgroup_inet6_connect(parameters);
return usersim_fwp_cgroup_inet6_connect(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_sock_ops_v4(_In_ fwp_classify_parameters_t* parameters, _Out_opt_ uint64_t* flow_id)
test_sock_ops_v4(_In_ const fwp_classify_parameters_t* parameters, _Out_opt_ uint64_t* flow_id)
{
return usersim_fwp_sock_ops_v4(parameters, flow_id);
return usersim_fwp_sock_ops_v4(const_cast<fwp_classify_parameters_t*>(parameters), flow_id);
}

FWP_ACTION_TYPE
test_sock_ops_v6(_In_ fwp_classify_parameters_t* parameters, _Out_opt_ uint64_t* flow_id)
test_sock_ops_v6(_In_ const fwp_classify_parameters_t* parameters, _Out_opt_ uint64_t* flow_id)
{
return usersim_fwp_sock_ops_v6(parameters, flow_id);
return usersim_fwp_sock_ops_v6(const_cast<fwp_classify_parameters_t*>(parameters), flow_id);
}

void
Expand All @@ -107,6 +110,18 @@ typedef class _netebpf_ext_helper
usersim_fwp_sock_ops_v4_remove_flow_context(flow_id);
}

FWP_ACTION_TYPE
test_cgroup_inet4_listen(_In_ const fwp_classify_parameters_t* parameters)
{
return usersim_fwp_cgroup_inet4_listen(const_cast<fwp_classify_parameters_t*>(parameters));
}

FWP_ACTION_TYPE
test_cgroup_inet6_listen(_In_ const fwp_classify_parameters_t* parameters)
{
return usersim_fwp_cgroup_inet6_listen(const_cast<fwp_classify_parameters_t*>(parameters));
}

private:
bool trace_initiated = false;
bool ndis_handle_initialized = false;
Expand Down
142 changes: 142 additions & 0 deletions tests/netebpfext_unit/netebpfext_unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,7 @@ TEST_CASE("sock_ops_context", "[netebpfext]")
REQUIRE(output_context.compartment_id == 0x12345679);
REQUIRE(output_context.interface_luid == 0x1234567890abcdee);
}

// Thread function for concurrent sock_ops invocation.
void
sock_ops_thread_function(
Expand Down Expand Up @@ -1242,4 +1243,145 @@ TEST_CASE("sock_ops_invoke_concurrent2", "[netebpfext_concurrent]")

REQUIRE(failure_count == 0);
}

TEST_CASE("sock_addr_listen_invoke", "[netebpfext]")
{
ebpf_extension_data_t npi_specific_characteristics = {
.header = EBPF_ATTACH_CLIENT_DATA_HEADER_VERSION,
};
test_sock_addr_client_context_header_t client_context_header = {0};
test_sock_addr_client_context_t* client_context = &client_context_header.context;
fwp_classify_parameters_t parameters = {};

netebpf_ext_helper_t helper(
&npi_specific_characteristics,
(_ebpf_extension_dispatch_function)netebpfext_unit_invoke_sock_addr_program,
(netebpfext_helper_base_client_context_t*)client_context);

netebpfext_initialize_fwp_classify_parameters(&parameters);

// Test listen operations that should be allowed (soft permit).
// Listen context has different field semantics (both msg_src and user contain local address).
client_context->sock_addr_action = SOCK_ADDR_TEST_ACTION_PERMIT_SOFT;
client_context->validate_sock_addr_entries = false;

FWP_ACTION_TYPE result = helper.test_cgroup_inet4_listen(&parameters);
REQUIRE(result == FWP_ACTION_PERMIT);

result = helper.test_cgroup_inet6_listen(&parameters);
REQUIRE(result == FWP_ACTION_PERMIT);

// Test listen operations that should be blocked.
client_context->sock_addr_action = SOCK_ADDR_TEST_ACTION_BLOCK;

result = helper.test_cgroup_inet4_listen(&parameters);
REQUIRE(result == FWP_ACTION_BLOCK);

result = helper.test_cgroup_inet6_listen(&parameters);
REQUIRE(result == FWP_ACTION_BLOCK);

// Test listen operations with hard permit.
client_context->sock_addr_action = SOCK_ADDR_TEST_ACTION_PERMIT_HARD;

result = helper.test_cgroup_inet4_listen(&parameters);
REQUIRE(result == FWP_ACTION_PERMIT);

result = helper.test_cgroup_inet6_listen(&parameters);
REQUIRE(result == FWP_ACTION_PERMIT);
}

TEST_CASE("sock_addr_listen_context", "[netebpfext]")
{
netebpf_ext_helper_t helper;
auto sock_addr_program_data = helper.get_program_info_provider_data(EBPF_PROGRAM_TYPE_CGROUP_SOCK_ADDR);
REQUIRE(sock_addr_program_data != nullptr);

size_t output_data_size = 0;

// Test listen context for IPv4 using bpf_sock_addr_t.
// For listen, both msg_src_* and user_* contain the local listen address.
bpf_sock_addr_t input_context_v4 = {};
input_context_v4.family = AF_INET;
input_context_v4.msg_src_ip4 = 0x7f000001; // 127.0.0.1 in host byte order.
input_context_v4.msg_src_port = htons(8080); // Port 8080.
input_context_v4.user_ip4 = 0x7f000001; // Same as msg_src for listen.
input_context_v4.user_port = htons(8080); // Same as msg_src for listen.
input_context_v4.protocol = IPPROTO_TCP;
input_context_v4.compartment_id = 0x12345678;
input_context_v4.interface_luid = 0x1234567890abcdef;

size_t output_context_size = sizeof(bpf_sock_addr_t);
bpf_sock_addr_t output_context = {};
bpf_sock_addr_t* sock_addr_context = nullptr;

REQUIRE(
sock_addr_program_data->context_create(
nullptr, 0, (const uint8_t*)&input_context_v4, sizeof(input_context_v4), (void**)&sock_addr_context) == 0);

// Verify the context was created correctly for listen.
REQUIRE(sock_addr_context->family == AF_INET);
REQUIRE(sock_addr_context->msg_src_ip4 == 0x7f000001);
REQUIRE(sock_addr_context->msg_src_port == htons(8080));
REQUIRE(sock_addr_context->user_ip4 == 0x7f000001);
REQUIRE(sock_addr_context->user_port == htons(8080));
REQUIRE(sock_addr_context->protocol == IPPROTO_TCP);

// Modify the context to test updates.
sock_addr_context->user_port = htons(9090);
sock_addr_context->compartment_id = 0x87654321;

output_context_size = sizeof(bpf_sock_addr_t);
output_data_size = 0;

sock_addr_program_data->context_destroy(
sock_addr_context, nullptr, &output_data_size, (uint8_t*)&output_context, &output_context_size);

REQUIRE(output_data_size == 0);
REQUIRE(output_context_size == sizeof(bpf_sock_addr_t));
REQUIRE(output_context.family == AF_INET);
REQUIRE(output_context.msg_src_ip4 == 0x7f000001);
REQUIRE(output_context.user_port == htons(9090)); // Modified value.
REQUIRE(output_context.compartment_id == 0x87654321); // Modified value.

// Test listen context for IPv6.
bpf_sock_addr_t input_context_v6 = {};
input_context_v6.family = AF_INET6;
uint32_t local_ipv6[4] = {0x00000000, 0x00000000, 0x00000000, 0x00000001}; // ::1 localhost.
memcpy(input_context_v6.msg_src_ip6, local_ipv6, sizeof(local_ipv6));
input_context_v6.msg_src_port = htons(443);
memcpy(input_context_v6.user_ip6, local_ipv6, sizeof(local_ipv6)); // Same as msg_src for listen.
input_context_v6.user_port = htons(443);
input_context_v6.protocol = IPPROTO_TCP;
input_context_v6.compartment_id = 0x11223344;
input_context_v6.interface_luid = 0xfedcba0987654321;

sock_addr_context = nullptr;
REQUIRE(
sock_addr_program_data->context_create(
nullptr, 0, (const uint8_t*)&input_context_v6, sizeof(input_context_v6), (void**)&sock_addr_context) == 0);

// Verify IPv6 listen context.
REQUIRE(sock_addr_context->family == AF_INET6);
REQUIRE(sock_addr_context->msg_src_ip6[0] == 0);
REQUIRE(sock_addr_context->msg_src_ip6[3] == 1);
REQUIRE(sock_addr_context->msg_src_port == htons(443));
REQUIRE(sock_addr_context->user_ip6[3] == 1);
REQUIRE(sock_addr_context->user_port == htons(443));
REQUIRE(sock_addr_context->protocol == IPPROTO_TCP);

output_context_size = sizeof(bpf_sock_addr_t);
output_data_size = 0;
memset(&output_context, 0, sizeof(output_context));

sock_addr_program_data->context_destroy(
sock_addr_context, nullptr, &output_data_size, (uint8_t*)&output_context, &output_context_size);

REQUIRE(output_context.family == AF_INET6);
REQUIRE(output_context.msg_src_ip6[3] == 1);
REQUIRE(output_context.msg_src_port == htons(443));
REQUIRE(output_context.user_ip6[3] == 1);
REQUIRE(output_context.user_port == htons(443));
REQUIRE(output_context.protocol == IPPROTO_TCP);
}

#pragma endregion sock_ops
4 changes: 2 additions & 2 deletions tests/sample/cgroup_sock_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ authorize_v6(bpf_sock_addr_t* ctx, void* connection_policy_map)
}

__inline int
authorize_listen_v4(bpf_sock_addr_t* ctx, void* connection_policy_map)
authorize_listen_v4(const bpf_sock_addr_t* ctx, void* connection_policy_map)
{
connection_tuple_t tuple_key = {0};
int* verdict = NULL;
Expand All @@ -103,7 +103,7 @@ authorize_listen_v4(bpf_sock_addr_t* ctx, void* connection_policy_map)
}

__inline int
authorize_listen_v6(bpf_sock_addr_t* ctx, void* connection_policy_map)
authorize_listen_v6(const bpf_sock_addr_t* ctx, void* connection_policy_map)
{
connection_tuple_t tuple_key = {0};
int* verdict;
Expand Down
Loading