fix(smolmachines): enforce per-bottle loopback isolation on Linux via iptables
On Linux, smolvm's TSI allowlist DB patch crashes boot, so force_allowlist is a no-op. This left the agent VM with full host loopback access — a security regression from the macOS behavior. Fix: install guest-side iptables rules in _init_vm that ACCEPT traffic to the bottle's allocated loopback alias (proxy_host/32) and DROP all other 127.0.0.0/8 destinations. The agent runs as non-root (node) and cannot flush the rules. - Add iptables to claude and codex agent Dockerfiles - Use DROP (not REJECT) — libkrun kernel lacks the REJECT module - Skip on macOS where force_allowlist handles it natively Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -601,8 +601,11 @@ class TestLaunchResourceWiring(unittest.TestCase):
|
||||
"bot_bottle.backend.smolmachines.launch._smolvm.machine_exec",
|
||||
) as machine_exec, patch(
|
||||
"bot_bottle.backend.smolmachines.launch._smolvm.wait_exec_ready",
|
||||
) as wait_exec_ready:
|
||||
_launch._init_vm(plan)
|
||||
) as wait_exec_ready, patch(
|
||||
"bot_bottle.backend.smolmachines.launch._loopback._is_macos",
|
||||
return_value=True,
|
||||
):
|
||||
_launch._init_vm(plan, "127.0.0.16")
|
||||
|
||||
machine_exec.assert_called_once()
|
||||
argv = machine_exec.call_args.args[1]
|
||||
@@ -610,6 +613,27 @@ class TestLaunchResourceWiring(unittest.TestCase):
|
||||
self.assertIn("chown -R node:node /home/node", argv[2])
|
||||
wait_exec_ready.assert_called_once_with(plan.machine_name)
|
||||
|
||||
def test_init_vm_installs_iptables_on_linux(self):
|
||||
plan = _plan()
|
||||
from bot_bottle.backend.smolmachines.smolvm import SmolvmRunResult
|
||||
with patch(
|
||||
"bot_bottle.backend.smolmachines.launch._smolvm.machine_exec",
|
||||
return_value=SmolvmRunResult(0, "", ""),
|
||||
) as machine_exec, patch(
|
||||
"bot_bottle.backend.smolmachines.launch._smolvm.wait_exec_ready",
|
||||
), patch(
|
||||
"bot_bottle.backend.smolmachines.launch._loopback._is_macos",
|
||||
return_value=False,
|
||||
):
|
||||
_launch._init_vm(plan, "127.0.0.16")
|
||||
|
||||
# Two calls: ownership repair + iptables
|
||||
self.assertEqual(2, machine_exec.call_count)
|
||||
iptables_argv = machine_exec.call_args_list[1].args[1]
|
||||
self.assertIn("iptables", iptables_argv[2])
|
||||
self.assertIn("127.0.0.16/32", iptables_argv[2])
|
||||
self.assertIn("127.0.0.0/8", iptables_argv[2])
|
||||
|
||||
|
||||
class TestPortLabels(unittest.TestCase):
|
||||
def test_known_and_dynamic_port_labels_round_trip(self):
|
||||
|
||||
Reference in New Issue
Block a user