Skip to content

Add bind classify variants that select the WFP filter by callout key#315

Draft
mikeagun wants to merge 1 commit into
microsoft:mainfrom
mikeagun:users/mikeagun/fwp-bind-select-by-callout
Draft

Add bind classify variants that select the WFP filter by callout key#315
mikeagun wants to merge 1 commit into
microsoft:mainfrom
mikeagun:users/mikeagun/fwp-bind-select-by-callout

Conversation

@mikeagun

@mikeagun mikeagun commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

fwp_engine_t::test_callout() selects a single WFP filter by (layer, sublayer)
first-match. When multiple callouts (each with its own filter) are registered at the
same WFP layer and sublayer, that first-match can dispatch to the wrong callout, so a
test cannot reliably target a specific callout.

Concrete case (ebpf-for-windows): the legacy bind hook callout and the new
CGROUP_SOCK_ADDR bind hook callout both register filters at
FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4/V6 with the default sublayer, so a sock_addr
bind test could pass while actually exercising the legacy bind callout.

Change

Add usersim_fwp_bind_ipv4_by_callout() / usersim_fwp_bind_ipv6_by_callout(), which
select the filter bound to a caller-supplied callout key via a new
get_fwpm_filter_by_callout_under_lock() helper. test_callout() and
test_bind_ipv4()/test_bind_ipv6() take an optional callout_key; when null, behavior
is unchanged (layer+sublayer first-match), so existing callers are unaffected.

Testing

Consumed and validated by the ebpf-for-windows netebpfext bind tests: a co-registration
test registers both bind callouts and verifies each bind entry dispatches to its intended
callout. usersim builds clean; existing callers are unaffected (default first-match path
unchanged).

mikeagun pushed a commit to mikeagun/ebpf-for-windows that referenced this pull request Jul 15, 2026
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
usersim's test_callout() selects a single WFP filter by (layer, sublayer)
first-match. When multiple callouts are registered at the same layer and
sublayer -- for example the legacy bind callout and the CGROUP_SOCK_ADDR
bind callout, both at ALE_RESOURCE_ASSIGNMENT -- that first-match can
dispatch to the wrong callout, so a test cannot reliably target a specific
callout.

Add usersim_fwp_bind_ipv4_by_callout() / usersim_fwp_bind_ipv6_by_callout(),
which select the filter bound to a caller-supplied callout key via a new
get_fwpm_filter_by_callout_under_lock() helper. test_callout() and
test_bind_ipv4()/test_bind_ipv6() take an optional callout_key; when null,
behavior is unchanged (layer+sublayer first-match), so existing callers are
unaffected.

This lets a consumer (e.g. the ebpf-for-windows netebpfext bind tests)
exercise a specific bind callout explicitly even when multiple bind callouts
share a WFP layer. The public _by_callout wrappers assert a non-null
callout_key.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c2ba0624-5e1d-4385-9972-eec1b8c595f1
@mikeagun
mikeagun force-pushed the users/mikeagun/fwp-bind-select-by-callout branch from 7537d02 to 6f836e8 Compare July 15, 2026 22:47
mikeagun pushed a commit to mikeagun/ebpf-for-windows that referenced this pull request Jul 15, 2026
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
@mikeagun
mikeagun requested a review from Copilot July 15, 2026 23:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the usersim WFP test harness to allow bind classify tests to target a specific callout when multiple callouts (and filters) coexist on the same WFP layer/sublayer, avoiding accidental dispatch to the wrong callout due to first-match ordering.

Changes:

  • Add optional callout_key parameters to fwp_engine_t::test_callout() and bind helpers to select a filter by callout key when provided.
  • Introduce get_fwpm_filter_by_callout_under_lock() to locate filters by (layer, calloutKey) instead of (layer, sublayer) first-match.
  • Add exported APIs usersim_fwp_bind_ipv4_by_callout() / usersim_fwp_bind_ipv6_by_callout() for callers that want explicit callout selection.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/fwp_um.h Adds optional callout_key plumbing and a helper to find a filter by callout key under lock.
src/fwp_um.cpp Implements callout-key-based filter selection in test_callout() and adds new exported bind-by-callout entry points.
inc/usersim/fwp_test.h Exposes the new bind-by-callout APIs to consumers with documentation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/fwp_um.h
Comment on lines +302 to +316
// Select a filter by its bound callout key at the given layer. This disambiguates the case where
// multiple callouts (each with its own filter) are registered at the same WFP layer and sublayer
// (e.g., the legacy bind callout and the CGROUP_SOCK_ADDR bind callout both at
// ALE_RESOURCE_ASSIGNMENT). Selecting the filter by its callout key lets a test target a specific
// callout explicitly instead of relying on layer+sublayer first-match ordering.
_Ret_maybenull_ const FWPM_FILTER*
get_fwpm_filter_by_callout_under_lock(_In_ const GUID& layer_guid, _In_ const GUID& callout_key)
{
for (auto& [first, filter] : fwpm_filters) {
if (memcmp(&filter.layerKey, &layer_guid, sizeof(GUID)) == 0 &&
memcmp(&filter.action.calloutKey, &callout_key, sizeof(GUID)) == 0 && filter.rawContext != 0) {
return &filter;
}
}
return nullptr;
Comment thread src/fwp_um.cpp
Comment on lines +1080 to +1085
FWP_ACTION_TYPE
usersim_fwp_bind_ipv4_by_callout(_In_ fwp_classify_parameters_t* parameters, _In_ const GUID* callout_key)
{
CXPLAT_DEBUG_ASSERT(callout_key != nullptr);
return fwp_engine_t::get()->test_bind_ipv4(parameters, callout_key);
}
Comment thread src/fwp_um.cpp
Comment on lines +1087 to +1092
FWP_ACTION_TYPE
usersim_fwp_bind_ipv6_by_callout(_In_ fwp_classify_parameters_t* parameters, _In_ const GUID* callout_key)
{
CXPLAT_DEBUG_ASSERT(callout_key != nullptr);
return fwp_engine_t::get()->test_bind_ipv6(parameters, callout_key);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

2 participants