Fix -x/--exec to also join a session's network namespace

net was deliberately excluded from exec_session.cpp's joinable_namespaces
list, written back when this project never isolated networking at
all. Now that -r/--run sometimes does (whenever -n/--network was
used), -x/--exec'ing into such a session saw the host's own network
stack instead of the container's -- confirmed directly: it showed the
host's unrelated listening ports and couldn't reach the container's
own service on 127.0.0.1.

Fixed by joining net the same way -x/--exec already joins
mnt/uts/ipc/pid/cgroup/user when they differ from the caller's own --
not required, so a session with no isolated net namespace (never
joined any network) is unaffected, the entry is just skipped like any
other identical-to-ours namespace.

Verified as root (via a scoped doas rule): execing into a session
joined to an extern network now correctly shows its own eth0 and
reaches its own service on 127.0.0.1; execing into a plain session
with no -n is unaffected.
This commit is contained in:
2026-08-30 13:39:25 +00:00
parent 7605831269
commit a9cd3bf643
3 changed files with 48 additions and 23 deletions
+29 -15
View File
@@ -686,19 +686,23 @@ Source layout (all under `src/`):
and an `extern` network simultaneously got two working interfaces
(`eth0`/`eth1`) with neither one breaking the other.
**Real, separate bug found while testing this commit, not yet fixed** (out
of scope for the networking feature's own commit sequence, noted here so
it isn't lost): `exec_session.cpp`'s `-x/--exec` deliberately never joins
the `net` namespace type (see that file's own entry below — written when
this project genuinely never isolated networking at all, so there was
nothing to join). Now that `-r/--run` sometimes *does* isolate networking
(whenever any `-n` was given), `-x/--exec`'ing into such a session sees the
*host's* network stack instead of the container's — confirmed directly:
execing into a session running a network-isolated `httpd` showed the
host's own unrelated listening ports and failed to reach the container's
own service on `127.0.0.1`. `exec_session.cpp` needs updating to join
`net` too, the same way it already joins `mnt`/`uts`/`ipc`/`pid`/`cgroup`/
`user` when they differ from the caller's own.
**Real, separate bug found while testing this commit — since fixed**
(`exec_session.{h,cpp}`, see that file's own entry below): `-x/--exec`
deliberately never joined the `net` namespace type, written back when this
project genuinely never isolated networking at all, so there was nothing
to join. Once `-r/--run` sometimes isolates networking (whenever any `-n`
was given), `-x/--exec`'ing into such a session saw the *host's* network
stack instead of the container's — confirmed directly: execing into a
session running a network-isolated `httpd` showed the host's own unrelated
listening ports and failed to reach the container's own service on
`127.0.0.1`. Fixed by joining `net` too, the same way `-x/--exec` already
joins `mnt`/`uts`/`ipc`/`pid`/`cgroup`/`user` when they differ from the
caller's own — reverified afterward: execing into that same session now
correctly shows the container's own `eth0` and reaches its own service on
`127.0.0.1`, while execing into a plain session with no `-n` at all is
unaffected (still just loopback, whether or not the kernel happened to
give it its own otherwise-empty net namespace via the default
`global.unshare-net` policy).
- `port_forward.{h,cpp}` — implements `-p`. `parse_port_forward_spec()`
splits `"[<network>:]<host-port>:<container-port>"` on `':'` (2 or 3
fields; the network name is deliberately restricted to excluding `':'` --
@@ -929,8 +933,18 @@ Source layout (all under `src/`):
(`sandbox_process.{h,cpp}` — moved out of this file once `--kill`
needed the exact same logic, see that entry) finds that real inner process
so this can join *its* namespaces instead. For each of `{mnt→--mount, uts→--uts, ipc→--ipc, pid→--pid,
cgroup→--cgroup, user→--user}` (`net` deliberately excluded — this project
never isolates networking, see `bwrap.cpp` below), `readlink()`s both
net→--net, cgroup→--cgroup, user→--user}` `net` used to be excluded here
(this project never isolated networking at all, back when this comment was
first written), but now that a session started with `-n/--network`
(`network_join.h`) genuinely does get an isolated net namespace, skipping
it left `-x/--exec` seeing the *host's* network stack instead of the
container's — confirmed directly (execing into a network-isolated session
showed the host's own unrelated listening ports and couldn't reach the
container's own service on `127.0.0.1`), fixed by including it the same
way as the other optional types: a session with no isolated net namespace
at all (i.e. `net` identical to ours) just has this entry skipped like any
other, so nothing changes for a session that never joined a network.
`readlink()`s both
`/proc/<ns_pid>/ns/<type>` and `/proc/self/ns/<type>` and only passes
nsenter's corresponding `--type=/proc/<ns_pid>/ns/<type>` flag when they
differ — an identical-namespace re-entry attempt can fail outright