fix(pasta): block host loopback access from the namespace when `--dis…#612
Conversation
…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>
34e48d4 to
371d148
Compare
| } | ||
| if d.disableHostLoopback { | ||
| opts = append(opts, "--no-map-gw") | ||
| opts = append(opts, "--no-map-gw", "--tcp-ns=none", "--udp-ns=none") |
There was a problem hiding this comment.
Doesn't it break port forwarding with implicit port driver?
There was a problem hiding this comment.
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 🙏
…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-loopbackis meant to do.The following demonstrates this behavior:
However,
--disable-host-loopbackis 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-loopbackto pasta's--no-map-gw.--no-map-gwblocks host access via the gateway, but it does not block the splice path (-T auto -U 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 noneto pasta as well.This prevents a process in the isolated namespace from reaching a process running on the host loopback.
After applying this fix: