Skip to content

apply-nftables.sh: control-plane isolation rule fails to parse cgroup path ("syntax error, unexpected /"), falls back to blocking all local access #83

Description

@sixtoad

Summary

internal/assets/apply-nftables.sh emits an nftables rule to block the target cgroup from reaching the leashd control plane, but nft rejects it with a syntax error when TARGET_CGROUP is a filesystem cgroup path (which contains /). leashd then falls back to blocking all local access to the control-plane port, degrading the intended cgroup-scoped isolation to a namespace-wide block.

Where

internal/assets/apply-nftables.sh, the leash:block-control-plane rule:

nft add rule inet leash out_filter socket cgroupv2 level 1 "$TARGET_CGROUP" \
    tcp dport $LEASH_PORT reject with tcp reset comment "leash:block-control-plane"

Observed

With TARGET_CGROUP set to a host cgroup path (e.g. /sys/fs/cgroup/system.slice/<unit>), on a Linux host whose kernel does support nft_socket cgroupv2:

Error: syntax error, unexpected /
add rule inet leash out_filter socket cgroupv2 level 1 /sys/fs/cgroup/system.slice/<unit> tcp dport 18080 reject with tcp reset comment leash:block-control-plane
                                                       ^
leash: WARNING: cgroup-based control plane isolation unavailable (nftables); blocking all local access to control plane port 18080
leash: blocked local access to control plane port 18080 (fallback nftables)

The caret points at the first / of the cgroup path.

Impact

The script's fallback still blocks the port for all local processes, so this is not a security regression — but:

  • the intended cgroup-scoped isolation is lost: every local process is blocked from the control-plane port, not just the target cgroup;
  • the alarming Error: / WARNING: output appears on every run.

This is distinct from the existing "kernel lacks nft_socket cgroupv2 support" fallback (e.g. LinuxKit on Docker Desktop). Here the kernel supports the match — the rule text itself fails to parse.

Likely cause

socket cgroupv2 level N <path> needs the path as an nft string literal (and, I believe, relative to the cgroup2 mount root — i.e. without the /sys/fs/cgroup prefix). The shell-level "$TARGET_CGROUP" quoting does not survive to nft (nft receives the bare path via argv and chokes on the /). Quoting the path in nft syntax and/or stripping the /sys/fs/cgroup prefix should fix it — but I have not confirmed the exact form the matcher wants.

Environment

  • Linux host, bpf in the active LSM list, nft_socket cgroupv2 support present
  • nftables (nft) available; the cgroup-scoped rule is attempted and the fallback is taken

Happy to test a proposed fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions