Skip to content

Kubernetes driver on WSL2 with mirrored networking: sandbox start fails with seccomp notification probe: Resource busy (os error 16) (follow-up to #3842) #4902

Open

Description

@mahonyyildiz

Follow-up to #3842, as suggested there once #4051 landed: with 0.1.5 the probe now reports the real errno, and on this host it is EBUSY.

User Story

I use OpenShell to run sandboxed browser desktops for AI agents on a single-node k3s cluster with the Kubernetes compute driver. I directly encountered sandbox creation failing on a WSL2 node that uses mirrored networking. This blocks every sandbox on that node.

Problem Statement

On a WSL2 host with networkingMode=mirrored, openshell sandbox create starts the sandbox pod (supplementalGroupsPolicy: Strict is accepted, the Landlock ABI and allow/deny probes pass), then the agent container exits with seccomp notification probe: Resource busy (os error 16). The message does not say what is wrong or what the operator should change.

Impact / Why This Matters

Every sandbox on such a node fails. To find out why, the operator has to read the probe source and inspect /proc/*/status on the node. The only workarounds are moving sandboxes to a non-WSL node or switching WSL to NAT networking, which changes networking for everything else on the host.

Evidence: every process on the node already carries one seccomp filter before any container starts.

Process Seccomp_filters
PID 1 (systemd), k3s-server, containerd, containerd-shim on the WSL2 node 1
A plain busybox pod with seccompProfile: RuntimeDefault on the WSL2 node 2
The same pod on a non-WSL k3s node (colima) 1

This matches the root cause found in #3842 and microsoft/WSL#9548 (mirrored networking installs a filter with a notification listener on PID 1). The same OpenShell release runs fine on the non-WSL node.

Acceptance Criteria

  • When installing the notification listener fails with EBUSY, the error says that a seccomp notification listener is already attached to the process tree and, on WSL2, names networkingMode=mirrored as the usual cause.
  • openshell doctor check flags Seccomp_filters > 0 on the node's PID 1, or the Windows/WSL guidance (docs(windows): establish branch-specific top-level Windows guidance #4755) states that WSL2 hosts need networkingMode=nat.
  • The docs state whether mirrored networking is supported by 0.1.x.

Reproduction Steps

  1. On Windows 11, set networkingMode=mirrored in .wslconfig and run single-node k3s inside WSL2.
  2. Install OpenShell 0.1.5 from oci://ghcr.io/nvidia/openshell/helm-chart with the Kubernetes compute driver.
  3. Run openshell sandbox create --name probe --cpu 250m --memory 512Mi -- sh -c 'sleep 86400'.

Environment

  • OpenShell: 0.1.5 (Helm chart 0.1.5), Agent Sandbox v1.0.8, Kubernetes compute driver
  • OS: Windows 11 + WSL2, kernel 6.18.54.1-microsoft-standard-WSL2, Ubuntu 24.04.4
  • Runtime: single-node k3s v1.35.3, containerd 2.2.2
  • WSL networking: mirrored
  • Kyverno baseline policies (privilege escalation, privileged containers, host namespaces) are enforced; the gateway, supervisor and sandbox pods pass them unchanged, which is great.

Logs

Error:   × seccomp notification probe
  ╰─▶ Resource busy (os error 16)

Question

#3842 reports that 0.0.116 worked with mirrored networking. Is a degraded mode without a NEW_LISTENER filter planned, or is the listener a hard requirement of the 0.1.x isolation model? The answer decides whether we move sandboxes off WSL nodes or change the networking mode.

Happy to run diagnostics on this host.

Activity

  1. O96a commented on Oct 24, 2026

    @O96a

    EBUSY means the thread you probed on already has a filter with a listener attached — the kernel supports notify fine, it just refuses a second SECCOMP_FILTER_FLAG_NEW_LISTENER on the same thread. So the probe is running somewhere that already installed one: either it fires twice (a retry after a partial failure, or a second probe call in the same process), or it lands on a recycled OS thread from the runtime's pool.

    The fix is to own the thread. Either lock a fresh goroutine:

    go func() {
        runtime.LockOSThread()
        defer runtime.UnlockOSThread()
        // probe here; the listener dies with this thread
    }()

    or fork a short-lived child and probe there so the listener can't outlive the check. Either way, treat EBUSY as "notify is available, someone already set it up," not "unsupported."

    Mirrored networking is a red herring — it changes the network namespace, not seccomp state. WSL2's kernel (5.15+) has seccomp user notif, and the same probe would fail identically on a bare-metal k3s node carrying the same thread-reuse bug. Worth checking whether the probe result is cached per-process or per-thread: if it's per-thread and the sandbox start path runs on a different thread than the one that probed, you get a second install attempt and the same EBUSY.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:triage-neededOpened without agent diagnostics and needs triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions