Skip to content

Commit 5bf1c64

Browse files
committed
network: fall back to blanket port block when cgroup isolation unavailable
LinuxKit (Docker Desktop) and OrbStack kernels lack xt_cgroup / nft cgroupv2 socket matching, causing leash to FATAL on startup. When cgroup-scoped filtering fails, block ALL outbound connections to the control plane port instead. This still prevents the target container from reaching leashd while external access via Docker port publishing is unaffected. Also fix nftables ensure_rule comment quoting — nft requires literal quotes around comment values containing colons. Closes #60
1 parent 0f4aa83 commit 5bf1c64

3 files changed

Lines changed: 45 additions & 14 deletions

File tree

internal/assets/apply-ip6tables.sh

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,25 @@ fi
6363
# SECURITY: This is a REQUIRED security control - failure is fatal.
6464
# Requires --cgroupns=host on the container to see host cgroup paths.
6565
if [ -n "$TARGET_CGROUP" ] && [ -n "$LEASH_PORT" ]; then
66-
if ! ensure_rule -t filter -C OUTPUT -m cgroup --path "$TARGET_CGROUP" -p tcp --dport "$LEASH_PORT" -j REJECT; then
66+
# Preferred: scope the block to the target container via cgroup matching.
67+
if ! ensure_rule -t filter -C OUTPUT -m cgroup --path "$TARGET_CGROUP" -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset; then
6768
if ip6tables_cmd -t filter -A OUTPUT -m cgroup --path "$TARGET_CGROUP" -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset 2>&1; then
6869
echo "leash: blocked target cgroup $TARGET_CGROUP from reaching control plane port $LEASH_PORT (ip6tables)"
6970
else
70-
echo "leash: FATAL: could not apply cgroup-based control plane isolation (IPv6)" >&2
71-
echo "leash: This security control is required to prevent target container from accessing leashd API" >&2
72-
exit 1
71+
# Fallback: some kernels (notably LinuxKit on Docker Desktop) lack xt_cgroup support.
72+
# In that case, block ALL local processes in this network namespace from connecting
73+
# to the control plane port. This preserves the security boundary at the cost of
74+
# disallowing in-namespace clients.
75+
echo "leash: WARNING: cgroup-based control plane isolation unavailable (IPv6); blocking all local access to control plane port $LEASH_PORT" >&2
76+
if ! ensure_rule -t filter -C OUTPUT -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset; then
77+
if ip6tables_cmd -t filter -A OUTPUT -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset 2>&1; then
78+
echo "leash: blocked local access to control plane port $LEASH_PORT (fallback IPv6)"
79+
else
80+
echo "leash: FATAL: could not apply control plane isolation (IPv6 cgroup and fallback failed)" >&2
81+
echo "leash: This security control is required to prevent target container from accessing leashd API" >&2
82+
exit 1
83+
fi
84+
fi
7385
fi
7486
fi
7587
fi
@@ -79,4 +91,3 @@ if [ "$RULE_ERRORS" -gt 0 ]; then
7991
echo "leash: WARNING: $RULE_ERRORS ip6tables rule(s) failed to apply (IPv6 network interception may be incomplete)" >&2
8092
fi
8193
exit 0
82-

internal/assets/apply-iptables.sh

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,25 @@ fi
6262
# SECURITY: This is a REQUIRED security control - failure is fatal.
6363
# Requires --cgroupns=host on the container to see host cgroup paths.
6464
if [ -n "$TARGET_CGROUP" ] && [ -n "$LEASH_PORT" ]; then
65-
if ! ensure_rule -t filter -C OUTPUT -m cgroup --path "$TARGET_CGROUP" -p tcp --dport "$LEASH_PORT" -j REJECT; then
65+
# Preferred: scope the block to the target container via cgroup matching.
66+
if ! ensure_rule -t filter -C OUTPUT -m cgroup --path "$TARGET_CGROUP" -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset; then
6667
if iptables_cmd -t filter -A OUTPUT -m cgroup --path "$TARGET_CGROUP" -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset 2>&1; then
6768
echo "leash: blocked target cgroup $TARGET_CGROUP from reaching control plane port $LEASH_PORT"
6869
else
69-
echo "leash: FATAL: could not apply cgroup-based control plane isolation" >&2
70-
echo "leash: This security control is required to prevent target container from accessing leashd API" >&2
71-
exit 1
70+
# Fallback: some kernels (notably LinuxKit on Docker Desktop) lack xt_cgroup support.
71+
# In that case, block ALL local processes in this network namespace from connecting
72+
# to the control plane port. This preserves the security boundary at the cost of
73+
# disallowing in-namespace clients.
74+
echo "leash: WARNING: cgroup-based control plane isolation unavailable; blocking all local access to control plane port $LEASH_PORT" >&2
75+
if ! ensure_rule -t filter -C OUTPUT -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset; then
76+
if iptables_cmd -t filter -A OUTPUT -p tcp --dport "$LEASH_PORT" -j REJECT --reject-with tcp-reset 2>&1; then
77+
echo "leash: blocked local access to control plane port $LEASH_PORT (fallback)"
78+
else
79+
echo "leash: FATAL: could not apply control plane isolation (cgroup and fallback failed)" >&2
80+
echo "leash: This security control is required to prevent target container from accessing leashd API" >&2
81+
exit 1
82+
fi
83+
fi
7284
fi
7385
fi
7486
fi

internal/assets/apply-nftables.sh

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ ensure_rule() {
5353
if nft_cmd list chain "$fam" "$tbl" "$chain" 2>/dev/null | grep -F "comment \"$comment\"" >/dev/null; then
5454
return 0
5555
fi
56-
if ! nft_cmd add rule "$fam" "$tbl" "$chain" "$@" comment "$comment" 2>/dev/null; then
56+
if ! nft_cmd add rule "$fam" "$tbl" "$chain" "$@" comment "\"$comment\"" 2>/dev/null; then
5757
echo "leash: WARNING: failed to add nftables rule $comment" >&2
5858
RULE_ERRORS=$((RULE_ERRORS + 1))
5959
return 1
@@ -93,9 +93,18 @@ if [ -n "$TARGET_CGROUP" ] && [ -n "$LEASH_PORT" ]; then
9393
elif nft_cmd 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" 2>&1; then
9494
echo "leash: blocked target cgroup $TARGET_CGROUP from reaching control plane port $LEASH_PORT (nftables)"
9595
else
96-
echo "leash: FATAL: could not apply cgroup-based control plane isolation (nftables)" >&2
97-
echo "leash: This security control is required to prevent target container from accessing leashd API" >&2
98-
exit 1
96+
# Fallback: some kernels (notably LinuxKit on Docker Desktop) lack nft_socket cgroupv2 support.
97+
# In that case, block ALL local processes in this network namespace from connecting to
98+
# the control plane port. This preserves the security boundary at the cost of disallowing
99+
# in-namespace clients.
100+
echo "leash: WARNING: cgroup-based control plane isolation unavailable (nftables); blocking all local access to control plane port $LEASH_PORT" >&2
101+
if ensure_rule inet leash out_filter "leash:block-control-plane-fallback" tcp dport $LEASH_PORT reject with tcp reset; then
102+
echo "leash: blocked local access to control plane port $LEASH_PORT (fallback nftables)"
103+
else
104+
echo "leash: FATAL: could not apply control plane isolation (nftables cgroup and fallback failed)" >&2
105+
echo "leash: This security control is required to prevent target container from accessing leashd API" >&2
106+
exit 1
107+
fi
99108
fi
100109
fi
101110

@@ -104,4 +113,3 @@ if [ "$RULE_ERRORS" -gt 0 ]; then
104113
echo "leash: WARNING: $RULE_ERRORS nftables rule(s) failed to apply (network interception may be incomplete)" >&2
105114
fi
106115
exit 0
107-

0 commit comments

Comments
 (0)