Repository navigation
dhcpcd in the net zone separates its privileges: its parsers run as a user of their own in an empty root, and a hook that trusts nothing writes the zone's resolv.conf - #245
Merged
Conversation
… user of their own in an empty root, and a hook that trusts nothing writes the zone's resolv.conf dhcpcd parsed every lease, DHCPv6 reply and router advertisement as the net zone's root, with that zone's capabilities, because the zone denied what its privilege separation needs. Now the net zone's policy keeps CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT (caps::PRIVSEP: kept together, by the nic zone alone), and those open setuid, setgid, setgroups and chroot in its filter (seccomp::CAP_CALLS) while every other zone's filter stays as it was. Its user namespace maps a third id, 100, to uid_base + 100 and allows setgroups, its passwd and group name dhcpcd there, and /var/empty is made on the root before it is sealed. dhcpcd's own seccomp filter then confines the parsers. The helper that stays root runs the hook with the environment the parsers send, so netzone-init.sh starts dhcpcd with Kryptik's hook instead of dhcpcd-run-hooks: it checks every value for form, keeps its state in /run/lease-dns, and writes only nameserver lines. dhcpcd -x leaves cleanup: the zone's root cannot signal the dhcpcd user, and the zone's end ends dhcpcd. The design doc said the opposite: that three capabilities for the hostile zone were a net loss with the zone as the sandbox. It now says what the helper still does for the parsers and what a parser bug no longer reaches.
…igits str.isdigit() is true for "²", which int() then refuses, so a lifetime like that from the unprivileged side crashed the hook before it rebuilt resolv.conf: nothing written, but a crash where a refusal was meant. The suite now sends one and needs the hook to exit 0 with the file unchanged.
The one conflict is zones-check.sh's net-dns line, which main now reads through the catch-all log's helpers; dhcpcd-separated follows it. With the merge, zones-test.sh lists dhcpcd-separated, and the comment over the setuid check says what stage 06 does since c431bf4: it fails the build on a bit the allowlist does not justify, where it used to strip it.
DevomB
marked this pull request as ready for review
October 9, 2026 02:02
CodeQL read the failure message of an assertion on passwd_for's output as cleartext logging of sensitive information. The synthesized passwd holds no secret, but the message adds nothing the assertion does not already say.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Owner's decision: merge (2026-10-09). This reverses a choice the design doc recorded; the owner weighed both sides below and said yes.
What was wrong. dhcpcd parsed every DHCP lease, DHCPv6 reply and router advertisement as the net zone's root, with the zone's capabilities:
CAP_NET_ADMIN,CAP_NET_RAW, the Wi-Fi credentials file, the broker's socket and the firewall's netlink socket all within reach of a parser bug. dhcpcd ships privilege separation, but the zone denied what it needs. The design doc called granting that a net loss: "the zone is the sandbox."What changed.
kryptikd:
caps::PRIVSEP(CAP_SETUID,CAP_SETGID,CAP_SYS_CHROOT) is keepable, by the nic zone alone (NIC_ONLY), and kept together or not at all (policy::parse).seccomp::CAP_CALLS: a kept capability opens the denied calls it serves (setuid;setgid,setgroups;chroot).widened_foradds them; every other zone's program is unchanged, and the denied list's doc names this as its one exception.isolate::write_id_mapsmaps a third id, 100 (SERVICE_ID), touid_base+ 100, and leavessetgroupsallowed, only on a root launch of a zone that keepsPRIVSEP.rootfs: that zone's passwd and group namedhcpcdat 100, home/var/empty, made on the root tmpfs before it is sealed.spawnpasses the flag through, andseccomp-tracebuilds the same filter.The net zone:
policy/net.seccompkeeps the three capabilities.netzone-init.shstarts dhcpcd with-c /usr/libexec/kryptik/dhcpcd-hook, and dropsdhcpcd -xfrom its cleanup (the zone's root cannot signal the dhcpcd user, and the zone's end ends dhcpcd).tools/net/dhcpcd-hook.pyreplaces dhcpcd-run-hooks. dhcpcd's root helper runs the hook with the environment the parsers send, so it checks every value for form (an interface name, a protocol from a list, IP literals with a scope only on that interface). It keeps its state in/run/lease-dns, outside what the helper writes for dhcpcd, and writes onlynameserverlines, by temp file and rename. Its paths come from the command line, which dhcpcd never fills.Tests and docs:
tools/tests/netzone-hook.shfeeds the hook hostile environments: words that are not addresses, a second line, a path as an interface, an unknown protocol, junk in its own state files,PYTHON*variables.zones-check.sh'sdhcpcd-separated: at least one dhcpcd process as host uiduid_base+ 100 in an empty root, with no effective capability and two seccomp filters; a root helper; and a lease file.net-zone.md,zone-policy-files.mdandstatus.mdsay what this does and costs.The trade.
no_new_privs, so a setuid binary grants nothing, and a chroot escape reaches only the zone's own tree./run/dhcpcdand/var/lib/dhcpcd.How the run proves it. Distro run 37681467342 on 42df7ff (main 68bf207 merged in) is green in every part: zones 83/0, with
dhcpcd-separated(parsers as uiduid_base+ 100 in an empty root, no capability, two filters, a root helper, a lease file),net-dns,routed-dns,net-lease-names-resolver,dns-follows-lease,wifi-leaseandwifi-associatedpassing.