Track implicit autobind ports from listen() in Consomme networking (#41125)
* Track implicit autobind ports from listen() in Consomme networking WSL2's Consomme networking mode only forwards TCP/UDP ports that were explicitly bind()'d in the guest. If an application calls listen() without first calling bind() (relying on the kernel's implicit autobind to an ephemeral port), the port tracker never sees it, so the port is never forwarded to the host and the socket is unreachable via 127.0.0.1:<port> from Windows. The seccomp filter that traps socket syscalls for port tracking only ever trapped bind(); this extends it to also trap listen() across all supported architectures (x86_64, x86 compat via socketcall, and ARM/ARM64), and dispatches it through the existing DeferredPortLookup/ResolvePortZeroBind mechanism already used for explicit bind(port=0). To avoid adding latency to the overwhelmingly common bind()+listen() sequence (where the port is already known), ParseListen first checks getsockname() synchronously and only falls back to the deferred resolution path for genuine implicit-autobind-via-listen() calls (no prior bind()). Adds ListenWithoutBindIsTracked test coverage in both Consomme and Mirrored NetworkTests suites. Fixes #41117 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 30cabf31-6198-44c8-b078-2a2ce1c6c56b * Fix clang-format violation in NetworkTests.cpp Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 30cabf31-6198-44c8-b078-2a2ce1c6c56b * Fix stale/inaccurate comments per Copilot review - Update RegisterSeccompHook doc comment to reference SIOCSIFFLAGS (matching the actual BPF filter) instead of the incorrect TUNSETIFF. - Update ParseListen's comment to reflect the getsockname() fast-path added before deferring resolution, instead of describing it as always deferring. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 30cabf31-6198-44c8-b078-2a2ce1c6c56b * Clarify RegisterSeccompHook doc comment scope per Copilot review ioctl(*, SIOCSIFFLAGS, *) is only trapped in the native 64-bit BPF block, not the 32-bit compat blocks (socketcall/ARMV7), which only trap bind()/listen(). Clarify the routine description accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 30cabf31-6198-44c8-b078-2a2ce1c6c56b * Fix potential port truncation race in ListenWithoutBindIsTracked test Only parse the PORT= value once the line is terminated by a newline, instead of stopping at the first non-digit character seen in a partial ReadFile() buffer. This avoids truncating the port number (e.g. reading "123" as "12") when the perl helper's output is split across multiple reads. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 85780ea9-1bf4-4997-8732-b33920e7d6b8 * Move network namespace read_symlink() into try block in ParseListen If the target process exits between the seccomp trap and this call, read_symlink() could throw outside of the try block, routing through the outer GetCallInfo catch/log path with a bind()-focused error message instead of the intended 'not an IP socket, let it through' handling used by the rest of ParseListen. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 10ce6d20-f8ca-4204-92a2-48e23bb6ee66 --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 30cabf31-6198-44c8-b078-2a2ce1c6c56b Copilot-Session: 85780ea9-1bf4-4997-8732-b33920e7d6b8 Copilot-Session: 10ce6d20-f8ca-4204-92a2-48e23bb6ee66