Repository navigation
v1.2.1
Ubuntu Hello v1.2.1 - Clean-Install Fix, Settings Env Hardening, Booted-OS + Footage Test Tiers
This release fixes the 1.2.0 package failing to configure on a clean Ubuntu 26.04, closes a local root-execution path through the polkit-elevated Settings process, stops the PAM module from hijacking the host process's syslog identity, makes the confirmations config migration run for package installs, corrects the mode of config.ini, and adds the two test tiers that found all of it: a booted-OS tier (a clean Ubuntu, Fedora or Arch under QEMU/KVM with an emulated TPM) and a recorded-footage tier (the real recognition loop on real camera frames, no face pixels kept). Plural-form translations are now linted and declared in every catalog.
π§ What's in this release
- π¦ Fix: fresh install failed on a clean Ubuntu 26.04. The package builds dlib from source (the archive has no
python3-dlib) and the toolchain it needs was only Recommended. apt never upgrades an already-installed package to satisfy a Recommends, so on an image whosepython3lagged the archivepython3-devwas silently skipped, the build died onPython.h: No such file or directory, dpkg stayed half-configured and every login fell through to the password. Developer machines that already had the headers never saw it. The toolchain is now a hard dependency unless the distro's dlib is installed (python3-dlib | python3-dev,| python3-pip,| cmake,| g++); Fedora/openSUSE gainpython3-devel/gcc-c++/ Pillow, Archgcc/python-pillow. Reproduced and verified on a clean cloud image. - π‘οΈ Security fix: the elevated Settings process accepted arbitrary environment variables from argv.
ubuntu-hello-gtkforwards the desktop's display and locale variables acrosspkexecas--env-KEY=valuearguments and restored every such argument into its environment as root. polkit pins only the interpreter and the script path, so a local user who can pass theauth_adminprompt could append--env-PATH=/tmp/evil:β¦or--env-LD_PRELOAD=β¦and have the root process β which spawnsubuntu-hello,sudo,gsettingsandloginctlby bare name β execute their binary as root. The restore now accepts only the fixed display/locale allowlist thatelevate()sends (one shared constant for sender and receiver), drops everything else with a stderr notice, and as root pinsPATHto a fixed system value before any helper is spawned. Reported by an automated security review; unit tests cover the injectedPATH/LD_*/PYTHON*/HOMEcases. - πͺ΅ Fix: the PAM module hijacked the host's syslog identity.
openlog("pam_ubuntu_hello")withoutcloselog()tagged every later line ofsudoor the display manager aspam_ubuntu_hello. The identity is now scoped to the module's own logging (SyslogIdentityScope). - βοΈ Fix: the
confirmationsmigration never ran for package installs. It lived in the source installer only;.deb/RPM/Arch upgrades left the key out and fell back to a single frame. It now lives inconfig_ensure.pyandpackage-configure.shruns it on every install and upgrade β hand edits, comments and a hand-tightened threshold are kept, verified on a real 1.1.6 β 1.2.1 apt upgrade. - π Fix:
config.iniwas installed executable (0755β0644);docs/SECURITY.mdnow describes the real/etc/ubuntu-hello/layout (0755 directory, secrets in 0700 subdirectories). - π Fix: on Fedora/Arch the module could break password authentication. The authselect/Arch PAM line used
[success=end default=ignore];endis a Debian pam-auth-update macro, not raw PAM syntax, so Linux-PAM let the module's skip return (AUTHINFO_UNAVAILfor SSH / no camera / disabled) surface β an SSH or camera-less login failed instead of falling through to the password. Now[success=done default=ignore]. Found with a live before/after on a booted Fedora guest. - π» Fix: face auth spawned a GTK overlay that crashed on a headless box.
compare.pystarted the on-screen auth overlay unconditionally, but under PAM there is no display, so on a server or SSHsudoit crashed on open and left an apport report every time (auth still fell back to the password). The overlay is now spawned only when a display is reachable. - πͺ Fix: the post-install wizard crashed on a headless machine. It assumed
DISPLAY=:0; installing over SSH started GTK with no display and left an apport crash report. It now launches only when a display actually exists. - π§© Fix: the Arch PAM module failed to load, breaking face auth entirely on Arch. It links
libINIReader.so.0(libinih) andlibevdev, but those were build-only deps, so pacman never installed them and PAM could notdlopenthe module. Both are now runtime dependencies. - ποΈ Fix: the Arch package could not build dlib and then skipped the security setup. Its deps listed
gcc/cmakebut notmake, so cmake could not build dlib, and that failure aborted the post-install before PAM and the polkit drop-in were written.makeis now a dependency and the dlib build runs last and non-fatally on every format, so the security config is always applied. - π§Ή Fix:
dnf removeleft/usr/lib64/ubuntu-hellobehind (untracked__pycache__); the shared pre-remove step now sweeps every lib dir and drops the emptied directory. - π₯οΈ New: booted-OS test tier (
scripts/vm/,tests/vm/). A clean Ubuntu 26.04, Fedora 44 or Arch cloud image boots under QEMU/KVM with a swtpm TPM 2.0 and scenario scripts run inside over SSH: install (PAM line, drop-in, tmpfiles, catalogs, dlib, file modes), config migration,sudothrough PAM with a synthetic model (fails closed without a camera, wrong password refused, caller environment never inherited, syslog identity kept), the greeter HARD RULE (pam_probe.pyruns the real PAM stack forgdm-passwordand counts prompts: withworkaround = offthe module never asks itself), the polkit helper sandbox with a real TPM seal/unseal, a real reboot, purge (nothing left, no crash reports), and an upgrade from the previous GitHub release. Onelib.shholds what differs per distro.UH_VM_PKG_DIRtests packages built from the tree; CI runs a matrix job per distro on release branches. Every fix above was found by it. - ποΈ New: recorded-footage test tier (
tests/footage/). Replays real-camera clips throughcompare.py's actual scan loop, the real dlib detector/predictor/encoder and the real nod rubber stamp: enrollment on real frames, the same face at Secure from another clip, no face never passing, the agreeing-frames gate, a real nod passing and holding still failing fail-closed, Secure margin. Privacy: only de-identified per-frame signals exist (dark flag, face rect, five landmarks, descriptor), the pixels were shredded, the signals stay off the repository, and CI uses a synthetic set with the measured shape. - π i18n: plural forms.
ngettext()entries were invisible to the lint and an untranslated plural shipped everywhere with the lint green; plural entries are now linted and every catalog header carries the language'sPlural-Formsrule so Python's gettext picks the right form. Catalogs are refreshed for 1.2.1 (template version, source references).
No new config keys or strings. Runtime dependencies: the dlib build toolchain is now a proper dependency where the distro ships no dlib. Desktop / greeter / wallet compatibility is unchanged.
π₯ Installation (from Release assets)
Verify downloads against SHA256SUMS on the Release page before installing. Download this release's assets into an empty/clean directory before running these commands β the wildcards below match by filename pattern, and leftover assets from another version in the same directory can make a package manager see multiple matches (or, for the AppImage command, pass a second matched file as a stray argument).
| Format | Command |
|---|---|
| Debian (amd64 + arm64) | sudo apt install ./ubuntu-hello_*_$(dpkg --print-architecture).deb ./ubuntu-hello-gtk_*_$(dpkg --print-architecture).deb |
| Fedora (amd64 + arm64) | sudo dnf install ./ubuntu-hello-[0-9]*fc44*.$(uname -m).rpm ./ubuntu-hello-gtk-*fc44*.$(uname -m).rpm |
| openSUSE (amd64 + arm64) | sudo zypper install ./ubuntu-hello-[0-9]*lp160*.$(uname -m).rpm ./ubuntu-hello-gtk-*lp160*.$(uname -m).rpm |
| AppImage (amd64 + arm64) | chmod +x Ubuntu-Hello-*-$(uname -m).AppImage && ./Ubuntu-Hello-*-$(uname -m).AppImage --install |
| Arch (amd64 only) | sudo pacman -U ./ubuntu-hello-[0-9]*.pkg.tar.zst ./ubuntu-hello-gtk-*.pkg.tar.zst |
| Snap (amd64 only) | sudo snap install --dangerous --classic ubuntu-hello_*_amd64.snap && sudo snap run ubuntu-hello.host-install |
| Flatpak (amd64 only) | flatpak install --user ./com.github.ventura8.UbuntuHello-*.flatpak && flatpak run --command=ubuntu-hello-host-install com.github.ventura8.UbuntuHello |
PPA remains available:
sudo add-apt-repository ppa:ventura8/ubuntu-hello && sudo apt update && sudo apt install ubuntu-helloOptional source install: download install.sh from the v1.2.1 tag, review it, then run locally β do not pipe a moving branch URL directly to bash.
Full Changelog: v1.2.0...v1.2.1