Skip to content

fix(pasta): block host loopback access from the namespace when `--dis…#612

Merged
AkihiroSuda merged 1 commit into
rootless-containers:masterfrom
haytok:block-host-lo-from-ns
Jul 26, 2026
Merged

fix(pasta): block host loopback access from the namespace when `--dis…#612
AkihiroSuda merged 1 commit into
rootless-containers:masterfrom
haytok:block-host-lo-from-ns

Conversation

@haytok

@haytok haytok commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

…able-host-loopback` is set

Currently, even when rootlesskit is run with
--net=pasta --disable-host-loopback, a process in the namespace created by pasta can reach a server listening on the loopback in the host namespace.

This goes against what --disable-host-loopback is meant to do.

The following demonstrates this behavior:

(host) $ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
(host) $ rootlesskit --net=pasta --copy-up=/etc --disable-host-loopback --port-driver=implicit --debug bash -c "curl localhost:8080 2>/dev/null | head -3"
...
DEBU[0000] [rootlesskit:parent] Executing [pasta --stderr --ns-ifname=tap0 --mtu=65520 --config-net --address=10.0.2.100 --netmask=24 --gateway=10.0.2.2 --dns-forward=10.0.2.3 --no-map-gw --ipv4-only --tcp-ports=auto --udp-ports=auto --host-lo-to-ns-lo 2777069]
...
<!DOCTYPE HTML>
<html lang="en">
<head>
...

However, --disable-host-loopback is meant to prevent a process in the isolated namespace created by pasta from reaching the server listening on the loopback in the host namespace.

So, the above connection is expected to fail.

Currently, rootlesskit translates --disable-host-loopback to pasta's --no-map-gw. --no-map-gw blocks host access via the gateway, but it does not block the splice path (-T auto -U auto).

> pasta --help | grep "forwarding\sto\sinit" -A 2
  -T, --tcp-ns SPEC	TCP port forwarding to init namespace
    SPEC is as described above
    default: auto
  -U, --udp-ns SPEC	UDP port forwarding to init namespace
    SPEC is as described above
    default: auto

As a result, a process in the isolated namespace can still reach the host loopback.

When rootlesskit is invoked with --disable-host-loopback, this commit passes -T none -U none to pasta as well.
This prevents a process in the isolated namespace from reaching a process running on the host loopback.

After applying this fix:

(host) $ rootlesskit --net=pasta --copy-up=/etc --disable-host-loopback --port-driver=implicit bash -c "curl localhost:8080"
WARN[0000] [rootlesskit:parent] "pasta" network driver is experimental. Needs very recent version of pasta (see docs/network.md).
curl: (7) Failed to connect to localhost port 8080 after 0 ms: Could not connect to server
...

…able-host-loopback` is set

Currently, even when rootlesskit is run with
`--net=pasta --disable-host-loopback`, a process in the namespace created
by pasta can reach a server listening on the loopback in the host
namespace.

This goes against what `--disable-host-loopback` is meant to do.

The following demonstrates this behavior:

```bash
(host) $ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

```

```
(host) $ rootlesskit --net=pasta --copy-up=/etc --disable-host-loopback --port-driver=implicit --debug bash -c "curl localhost:8080 2>/dev/null | head -3"
...
DEBU[0000] [rootlesskit:parent] Executing [pasta --stderr --ns-ifname=tap0 --mtu=65520 --config-net --address=10.0.2.100 --netmask=24 --gateway=10.0.2.2 --dns-forward=10.0.2.3 --no-map-gw --ipv4-only --tcp-ports=auto --udp-ports=auto --host-lo-to-ns-lo 2777069]
...
<!DOCTYPE HTML>
<html lang="en">
<head>
...
```

However, `--disable-host-loopback` is meant to prevent a process in the
isolated namespace created by pasta from reaching the server listening on
the loopback in the host namespace.

So, the above connection is expected to fail.

Currently, rootlesskit translates `--disable-host-loopback` to pasta's `--no-map-gw`.
`--no-map-gw` blocks host access via the gateway, but it does not block
the splice path (`-T auto -U auto`).

```bash
> pasta --help | grep "forwarding\sto\sinit" -A 2
  -T, --tcp-ns SPEC	TCP port forwarding to init namespace
    SPEC is as described above
    default: auto
  -U, --udp-ns SPEC	UDP port forwarding to init namespace
    SPEC is as described above
    default: auto
```

As a result, a process in the isolated namespace can still reach the host loopback.

When rootlesskit is invoked with `--disable-host-loopback`, this commit
passes `-T none -U none` to pasta as well.
This prevents a process in the isolated namespace from reaching a process
running on the host loopback.

After applying this fix:

```bash
(host) $ rootlesskit --net=pasta --copy-up=/etc --disable-host-loopback --port-driver=implicit bash -c "curl localhost:8080"
WARN[0000] [rootlesskit:parent] "pasta" network driver is experimental. Needs very recent version of pasta (see docs/network.md).
curl: (7) Failed to connect to localhost port 8080 after 0 ms: Could not connect to server
...
```

Signed-off-by: Hayato Kiwata <dev@haytok.jp>
@haytok
haytok force-pushed the block-host-lo-from-ns branch from 34e48d4 to 371d148 Compare July 20, 2026 14:41
@AkihiroSuda AkihiroSuda added this to the v3.0.3 milestone Jul 23, 2026
}
if d.disableHostLoopback {
opts = append(opts, "--no-map-gw")
opts = append(opts, "--no-map-gw", "--tcp-ns=none", "--udp-ns=none")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't it break port forwarding with implicit port driver?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review!

No, it doesn't.

-T/-U (--tcp-ns/--udp-ns) and -t/-u (--tcp-ports/--udp-ports) handle opposite directions, and this PR only touches the former.

Even when specifying --disable-host-loopback, --port-driver=implicit uses --tcp-ports=auto --udp-ports=auto, which forwards connections from the host to the isolated namespace. (ref)

On the other hand, --tcp-ns/--udp-ns configure port forwarding from the isolated namespace to the host, so passing --tcp-ns=none --udp-ns=none blocks only that path, and the inbound implicit port forwarding keeps working.

Note that after applying this fix, I've confirmed that we can access the server in the isolated namespace from the host via port forwarding as follows:

(host) > rootlesskit --copy-up=/etc --disable-host-loopback \
--net=pasta --port-driver=implicit \
python3 -m http.server 8080
WARN[0000] [rootlesskit:parent] "pasta" network driver is experimental. Needs very recent version of pasta (see docs/network.md).
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...

(host) > curl -4 localhost:8080  2>/dev/null | head -3
<!DOCTYPE HTML>
<html lang="en">
<head>

Please let me know if I've misunderstood your question 🙏

@AkihiroSuda AkihiroSuda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@AkihiroSuda
AkihiroSuda merged commit e98a3a3 into rootless-containers:master Jul 26, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants