Implement sock_addr bind hook usermode tests#5300
Conversation
18342c0 to
6b6f416
Compare
… type The netebpfext fuzzer's hook client attaches to ALL hook providers via the generic EBPF_HOOK_EXTENSION_IID NPI, including providers for different program types that share a WFP layer. With the listen hook in this PR plus the bind hook that recently landed on main, a fuzzer iteration that selects BPF_PROG_TYPE_CGROUP_SOCK_ADDR and invokes test_cgroup_inet4_listen would also match the CGROUP_SOCK_ADDR bind callout (same WFP layer scenario as ALE_RESOURCE_ASSIGNMENT_V4 vs the legacy bind callout). The same stack-buffer -overflow class of bug applies symmetrically: the listen path's classify dispatch could hit the bind callout's context size mismatch. Fix: add a desired_program_type field to netebpfext_helper_base_client_context_t and filter in _hook_client_attach_provider. The helper constructor accepts an optional bpf_prog_type_t, auto-derives the program type GUID from the registered program_info providers, and sets desired_program_type before registering the hook client. This is a general solution that prevents cross-type context mismatches for any future hooks that share a WFP layer. This change mirrors the equivalent fix applied to the bind tests PR (microsoft#5300) so the two PRs land with consistent listen+bind fuzzer safety regardless of merge order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6b6f416 to
254961e
Compare
… type The netebpfext fuzzer's hook client attaches to ALL hook providers via the generic EBPF_HOOK_EXTENSION_IID NPI, including providers for different program types that share a WFP layer. With the listen hook in this PR plus the bind hook that recently landed on main, a fuzzer iteration that selects BPF_PROG_TYPE_CGROUP_SOCK_ADDR and invokes test_cgroup_inet4_listen would also match the CGROUP_SOCK_ADDR bind callout (same WFP layer scenario as ALE_RESOURCE_ASSIGNMENT_V4 vs the legacy bind callout). The same stack-buffer -overflow class of bug applies symmetrically: the listen path's classify dispatch could hit the bind callout's context size mismatch. Fix: add a desired_program_type field to netebpfext_helper_base_client_context_t and filter in _hook_client_attach_provider. The helper constructor accepts an optional bpf_prog_type_t, auto-derives the program type GUID from the registered program_info providers, and sets desired_program_type before registering the hook client. This is a general solution that prevents cross-type context mismatches for any future hooks that share a WFP layer. This change mirrors the equivalent fix applied to the bind tests PR (microsoft#5300) so the two PRs land with consistent listen+bind fuzzer safety regardless of merge order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
254961e to
32da892
Compare
… type The netebpfext fuzzer's hook client attaches to ALL hook providers via the generic EBPF_HOOK_EXTENSION_IID NPI, including providers for different program types that share a WFP layer. With the listen hook in this PR plus the bind hook that recently landed on main, a fuzzer iteration that selects BPF_PROG_TYPE_CGROUP_SOCK_ADDR and invokes test_cgroup_inet4_listen would also match the CGROUP_SOCK_ADDR bind callout (same WFP layer scenario as ALE_RESOURCE_ASSIGNMENT_V4 vs the legacy bind callout). The same stack-buffer -overflow class of bug applies symmetrically: the listen path's classify dispatch could hit the bind callout's context size mismatch. Fix: add a desired_program_type field to netebpfext_helper_base_client_context_t and filter in _hook_client_attach_provider. The helper constructor accepts an optional bpf_prog_type_t, auto-derives the program type GUID from the registered program_info providers, and sets desired_program_type before registering the hook client. This is a general solution that prevents cross-type context mismatches for any future hooks that share a WFP layer. This change mirrors the equivalent fix applied to the bind tests PR (microsoft#5300) so the two PRs land with consistent listen+bind fuzzer safety regardless of merge order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… type The netebpfext fuzzer's hook client attaches to ALL hook providers via the generic EBPF_HOOK_EXTENSION_IID NPI, including providers for different program types that share a WFP layer. With the listen hook in this PR plus the bind hook that recently landed on main, a fuzzer iteration that selects BPF_PROG_TYPE_CGROUP_SOCK_ADDR and invokes test_cgroup_inet4_listen would also match the CGROUP_SOCK_ADDR bind callout (same WFP layer scenario as ALE_RESOURCE_ASSIGNMENT_V4 vs the legacy bind callout). The same stack-buffer -overflow class of bug applies symmetrically: the listen path's classify dispatch could hit the bind callout's context size mismatch. Fix: add a desired_program_type field to netebpfext_helper_base_client_context_t and filter in _hook_client_attach_provider. The helper constructor accepts an optional bpf_prog_type_t, auto-derives the program type GUID from the registered program_info providers, and sets desired_program_type before registering the hook client. This is a general solution that prevents cross-type context mismatches for any future hooks that share a WFP layer. This change mirrors the equivalent fix applied to the bind tests PR (microsoft#5300) so the two PRs land with consistent listen+bind fuzzer safety regardless of merge order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
32da892 to
b03dab7
Compare
…ters_t* Update all 12 test_* helpers in netebpf_ext_helper.h to take a const fwp_classify_parameters_t* (was non-const). Body uses const_cast to bridge to the underlying non-const usersim_fwp_* API. This enforces the immutability discipline at the wrapper boundary so callers cannot accidentally rely on per-call mutation of the shared parameters object (e.g., the sock_addr_invoke_bind test reuses one parameters object across multiple v4/v6 calls; without const, a mutation inside one call could silently affect the next). Scope: all helpers in this file for in-file consistency. Touched helpers (unchanged behavior, signature only): test_bind_ipv4 / test_bind_ipv6 test_cgroup_inet4_bind / test_cgroup_inet6_bind test_cgroup_inet4_recv_accept / test_cgroup_inet6_recv_accept test_cgroup_inet4_connect / test_cgroup_inet6_connect test_cgroup_inet4_connect_authorization / test_cgroup_inet6_connect_authorization test_sock_ops_v4 / test_sock_ops_v6 (flow_id out-param remains non-const) Addresses review comments from @dthaler on PR microsoft#5300: - thread PRRT_kwDOFTPWZc6ImFRO (tests/netebpfext_unit/netebpf_ext_helper.h:60) - thread PRRT_kwDOFTPWZc6ImGRk (FYI explaining v4/v6 reuse rationale) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… type The netebpfext fuzzer's hook client attaches to ALL hook providers via the generic EBPF_HOOK_EXTENSION_IID NPI, including providers for different program types that share a WFP layer. With the listen hook in this PR plus the bind hook that recently landed on main, a fuzzer iteration that selects BPF_PROG_TYPE_CGROUP_SOCK_ADDR and invokes test_cgroup_inet4_listen would also match the CGROUP_SOCK_ADDR bind callout (same WFP layer scenario as ALE_RESOURCE_ASSIGNMENT_V4 vs the legacy bind callout). The same stack-buffer -overflow class of bug applies symmetrically: the listen path's classify dispatch could hit the bind callout's context size mismatch. Fix: add a desired_program_type field to netebpfext_helper_base_client_context_t and filter in _hook_client_attach_provider. The helper constructor accepts an optional bpf_prog_type_t, auto-derives the program type GUID from the registered program_info providers, and sets desired_program_type before registering the hook client. This is a general solution that prevents cross-type context mismatches for any future hooks that share a WFP layer. This change mirrors the equivalent fix applied to the bind tests PR (microsoft#5300) so the two PRs land with consistent listen+bind fuzzer safety regardless of merge order. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Please resolve the merge conflicts and comments. Will review after that. |
Adds netebpfext_unit tests (6 test cases) and fuzzer coverage for the CGROUP_INET4/6_BIND sock_addr-aligned bind hook. Requires usersim bump for usersim_fwp_bind_ipv6() API and fixed test_callout() dispatch by filter calloutKey. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ters_t* Update all 12 test_* helpers in netebpf_ext_helper.h to take a const fwp_classify_parameters_t* (was non-const). Body uses const_cast to bridge to the underlying non-const usersim_fwp_* API. This enforces the immutability discipline at the wrapper boundary so callers cannot accidentally rely on per-call mutation of the shared parameters object (e.g., the sock_addr_invoke_bind test reuses one parameters object across multiple v4/v6 calls; without const, a mutation inside one call could silently affect the next). Scope: all helpers in this file for in-file consistency. Touched helpers (unchanged behavior, signature only): test_bind_ipv4 / test_bind_ipv6 test_cgroup_inet4_bind / test_cgroup_inet6_bind test_cgroup_inet4_recv_accept / test_cgroup_inet6_recv_accept test_cgroup_inet4_connect / test_cgroup_inet6_connect test_cgroup_inet4_connect_authorization / test_cgroup_inet6_connect_authorization test_sock_ops_v4 / test_sock_ops_v6 (flow_id out-param remains non-const) Addresses review comments from @dthaler on PR microsoft#5300: - thread PRRT_kwDOFTPWZc6ImFRO (tests/netebpfext_unit/netebpf_ext_helper.h:60) - thread PRRT_kwDOFTPWZc6ImGRk (FYI explaining v4/v6 reuse rationale) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
8cd6558 to
42ccd0a
Compare
| // (FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4). usersim's test_callout uses the filter's bound | ||
| // calloutKey to dispatch to the correct callout, so this routes to whichever bind hook | ||
| // currently has an attached client (legacy or CGROUP_SOCK_ADDR). | ||
| return usersim_fwp_bind_ipv4(const_cast<fwp_classify_parameters_t*>(parameters)); |
There was a problem hiding this comment.
I think this helper is still ambiguous and does not prove that the CGROUP_SOCK_ADDR bind callout is what runs here.
Provenance
- This helper calls
usersim_fwp_bind_ipv4()here. usersim_fwp_bind_ipv4()goes throughfwp_engine_t::test_bind_ipv4(), which invokestest_callout(FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4, FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4, _default_sublayer, ...)(external/usersim/src/fwp_um.cpp:133-151).- usersim then selects a filter by only
(layerKey, subLayerKey)inget_fwpm_filter_with_context_under_lock()(external/usersim/src/fwp_um.h:290-298). - Both the legacy bind filter (
netebpfext/net_ebpf_ext_bind.c:22-32) and the new sock_addr bind filter (netebpfext/net_ebpf_ext_sock_addr.c:605-617) register onFWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4with the default sublayer.
Because both filters share the same (layer, sublayer) key, usersim_fwp_bind_ipv4() does not uniquely select net_ebpf_extension_sock_addr_bind_classify(). That means test_cgroup_inet4_bind() can pass while still exercising the legacy bind path instead of the new sock_addr bind path. Could we add a dedicated usersim entry point, or otherwise select the sock_addr bind callout explicitly?
There was a problem hiding this comment.
In the current code it will dispatch correctly because the tests only attach the relevant callouts, but that is a good point that there is a latent bug that could trigger selection of the wrong classify function with future code changes.
I'll create a usersim PR to enable explicit selection of the correct callout.
The netebpfext bind test helpers routed through usersim_fwp_bind_ipv4() / usersim_fwp_bind_ipv6(), which select a WFP filter by (layer, sublayer) first-match. The legacy bind hook and the CGROUP_SOCK_ADDR bind hook both register filters at ALE_RESOURCE_ASSIGNMENT with the default sublayer, so when both are registered that first-match could dispatch to the wrong callout -- a sock_addr bind test could pass while exercising the legacy bind path. Route the bind helpers through the new usersim_fwp_bind_ipv4/ipv6_by_callout() entry points, which select the filter by its bound callout key: test_cgroup_inet4/6_bind() target the CGROUP_SOCK_ADDR bind callout and test_bind_ipv4/ipv6() target the legacy bind callout. Add sock_addr_bind_callout_disambiguation, which co-registers both bind hooks and verifies each bind entry dispatches to its intended callout. Addresses review feedback from @Alan-Jowett on microsoft#5300. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c2ba0624-5e1d-4385-9972-eec1b8c595f1
Point external/usersim at the branch adding usersim_fwp_bind_ipv4/ipv6_by_callout(), used by the netebpfext bind tests to select a bind callout explicitly. Temporary: this points at the fork branch pending the usersim change landing upstream, after which external/usersim will be re-pointed to usersim main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c2ba0624-5e1d-4385-9972-eec1b8c595f1
usersim_fwp_bind_ipv4/ipv6_by_callout() is not yet in usersim upstream. Point the external/usersim submodule URL at the mikeagun/usersim fork so CI can resolve the submodule commit while microsoft/usersim#315 is in review. Revert to https://github.com/microsoft/usersim.git once microsoft#315 lands. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c2ba0624-5e1d-4385-9972-eec1b8c595f1
91c73a7 to
a01968f
Compare
Description
Follow-up to #333
Closes #5327
Adds usermode unit tests and fuzzer coverage for the sock_addr-aligned bind hook
(
BPF_CGROUP_INET4/6_BIND) introduced in PR #5272.Depends on:
usersim_fwp_bind_ipv6()andtest_callout()calloutKey dispatch fixChanges:
usersim_fwp_bind_ipv6()and fixed multi-callout-per-layerdispatch in
test_callout()bpf_sock_addr_get_network_contextat bind layer,set_redirect_contextrejectiontest_cgroup_inet4_bind/test_cgroup_inet6_bindinnetebpfext_fuzzer
Testing
This PR adds usersim tests for the bind hook.
If new tests were added:
Documentation
N/A
Installation
N/A