feat(linux): run systemd service as unprivileged numa user #118
Reference in New Issue
Block a user
Delete Branch "feat/linux-drop-privileges"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
DynamicUser=yes+CAP_NET_BIND_SERVICE. A DNS-parser RCE now stays contained to what the service account can read/write, not the whole box.ProtectSystem=strict,PrivateTmp,PrivateDevices,ProtectKernel*,ProtectControlGroups,NoNewPrivileges,RestrictSUIDSGID,RestrictRealtime,RestrictAddressFamilies(AF_INET/INET6/UNIX/NETLINK).SystemCallFilterleft off for now — layered in a follow-up after isolated testing.install_service_binary_linux()stages the binary to/usr/local/bin/numawhencurrent_exe()sits on a path the transient UID can't traverse (e.g./home/<user>/…mode 0700,~/.cargo/bin). Linuxbrew's 0755 paths are kept in place. Atomiccopy + renameavoids ETXTBSY on re-install.systemctl restart(notstart) so upgrades pick up the new binary while the old one is running.Why it's safe
Runtime doesn't need root on Linux —
network_watch_loop(src/serve.rs:535) only reads/etc/resolv.conf, and all system-DNS mutation stays in the installer (install_linux/uninstall_linux), which continues to run as root via sudo.Why
DynamicUserinstead of a staticnumauserNo PKGBUILD/sysusers plumbing, no
useraddidempotency, no manual chown for legacy installs — systemd remapsStateDirectoryownership to the transient UID on each launch, including root-owned trees from pre-drop installs.Behavior change
Custom configs at
/root/.config/numa/numa.tomlwon't be loaded after upgrade — underDynamicUser,$HOMEis not/root, sosuggested_config_path()falls back to/var/lib/numa/numa.toml. Daemon falls back to defaults — safe degradation. Move custom configs to/var/lib/numa/numa.tomlto preserve.Follow-ups (separate PRs)
ConfigurationDirectory=/etc/numaintoload_configsearch paths (declared in the unit but currently unused).SystemCallFilter=@system-service+LockPersonality+ProcSubset=pidonce tested.obj= LocalSystem→LocalService, pullnetshout of the runtime.UserName+sandbox_init.packaging/systemd/on a future branch.Test plan
Covered by
integration-linuxCI:digon port 53MainPIDofnumadoes not run asroot(the invariant this PR establishes)Manual verification:
/var/lib/numa) — systemd migrates state~/build/numawith~mode 0700 → binary copied to/usr/local/bin/numa