Skip to content

A NIC the net zone renamed is renamed nic<N> before the next net zone takes it - #304

Merged
DevomB merged 2 commits into
mainfrom
nic-renamed-plain
Oct 9, 2026
Merged

DevomB merged 2 commits into
mainfrom
nic-renamed-plain

Conversation

@DevomB

@DevomB DevomB commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

What was wrong. The net zone holds CAP_NET_ADMIN in its own namespace, so it can rename its NIC to anything the kernel's dev_valid_name takes. That excludes only /, : and whitespace, so a leading dash, a quote, an escape and bytes that aren't UTF-8 all pass. When the zone ends, the kernel returns the NIC to zone 0 under that name, and the next start handed it on as it was. A compromised net zone could therefore shape the zone that replaces it:

  • A name that isn't UTF-8 failed every later start. physical_interfaces_under read names with to_string_lossy, so carry_nic looked up a name that does not exist. The net zone crash-looped and the machine stayed offline until a reboot; the restart meant to give a fresh zone did not.
  • Any other name reached the fresh zone's netzone-init.sh. A quote ended the name in the nft uplink set ("$n" at line 52), so x","kryptik0 puts the bridge in it. A leading dash reached dhcpcd as an option ("$@").

What changed.

  • compartments/kryptikd/src/netzone.rs: physical_interfaces_under returns each physical interface's name as the kernel holds it (an OsString), with its index from sysfs. physical_interfaces passes on a plain name (a lower-case letter, then lower-case letters and digits, as the kernel and eudev name NICs, and not kryptik0: the start makes that bridge in the zone after the NICs move, and a NIC by that name would fail it with EEXIST). It renames any other name to the kernel's nic%d template by index before the NIC moves, and logs the old name escaped. A returned NIC is down, as a rename needs. One that cannot be renamed is left in zone 0, with the reason logged.
  • compartments/kryptikd/src/netlink.rs: rename_index (RTM_NEWLINK with IFLA_IFNAME by index) and name_of (if_indextoname).
  • tools/net/netzone-init.sh: uplink_addr names the device to ip with dev, so a plain name that is also an ip keyword, such as up, is still read as a name.
  • Tests:
    • netzone::tests::only_plain_names_pass_on covers the class, including -k, x","kryptik0, an escape, kryptik0 and \xff.
    • netlink::tests::rename_by_index_takes_a_template makes a veth named x"y in a user and network namespace of its own, renames it by index to nic%d, and reads back nic0 under the same index.
  • build/guest-tests/zones-check.sh: the new check uplink-renamed-plain renames the net zone's NIC -x"y from inside the zone and stops the service. It sees the NIC back in zone 0 under that name, starts the service again, and passes only on a new READY line with uplinks=nic<N> and nothing left in zone 0. Then it stops the service, names the NIC eth0 again and restarts, for the checks that follow.
  • tools/image/zones-test.sh: lists the verdict on a line of its own, which merges with Every claim in docs/architecture.md about what zones cannot share or reach has a guest check #280's, The net zone runs on one CPU's worth of time, and the zones suite reads its limit back #295's and The clock query and the update fetcher give up every capability before they read from the network #300's changes to that list.
  • docs/design/net-zone.md: the gateway-failure bullet on what comes back to zone 0, and the tests.

How the run proves it. CI runs both unit tests. On main the rename test does not compile, as rename_index is new. In the Distro run's zones suite, uplink-renamed-plain fails on main: the next start hands -x"y to netzone-init.sh, whose nft set does not parse, so the zone reports NOT READY and dhcpcd takes the name as options. With this change the zone comes up READY on nic0.

Reported by linux-distro-fe, who widened it from the crash loop to the nft set and dhcpcd.

DevomB added 2 commits October 9, 2026 05:09
The net zone holds CAP_NET_ADMIN in its namespace and can give its NIC any
name the kernel takes: a leading dash, a quote, an escape, bytes that are
not UTF-8. When the zone ends the NIC comes back to zone 0 under that name,
and the next start handed it on as it was. A name that is not UTF-8 failed
every later start, since kryptikd looked up the lossy copy, and kept the
machine offline until a reboot. Any other reached the fresh zone's script:
a quote ended the name in the nft uplink set and could add kryptik0 to it,
and a leading dash reached dhcpcd as an option.

kryptikd now reads each physical interface's name as the kernel holds it,
with its index, and renames one that is not plain, a lower-case letter then
lower-case letters and digits, to the kernel's nic%d before it moves.
netzone-init.sh names the device to ip with dev, so a plain name that is
also an ip keyword is still read as a name.
DevomB added a commit that referenced this pull request Oct 9, 2026
An altname sits in the same name table as names and moves with the NIC,
so a net zone that gave its NIC the altname kryptik0 stopped every later
start making the bridge, as #304's plain names otherwise prevent. The
alias is free text that ip link prints. reset_nic now reads both with
RTM_GETLINK, removes the altnames with RTM_DELLINKPROP and drops the
alias with the address and MTU.

mac_of was test-only, which the release build refused.
@DevomB
DevomB marked this pull request as ready for review October 9, 2026 13:21
@DevomB
DevomB merged commit 0087625 into main Oct 9, 2026
21 checks passed
@DevomB
DevomB deleted the nic-renamed-plain branch October 9, 2026 15:20
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.

1 participant