fix(desktop): repair the Chromium sandbox on Ubuntu 24.04+ - #142
Merged
Merged
Conversation
The .deb installs chrome-sandbox 0755 on Ubuntu 24.04+, so the first launch by an ordinary user aborts: FATAL:setuid_sandbox_host.cc(163)] The SUID sandbox helper binary was found, but is not configured correctly. electron-builder's stock postinst chooses between the namespace sandbox and the SUID helper with `unshare --user true`. A postinst runs as root, and kernel.apparmor_restrict_unprivileged_userns restricts *unprivileged* user namespaces only — root is exempt. The probe therefore succeeds at install time, the postinst concludes the SUID helper is unnecessary, and drops the setuid bit. The app then runs as a normal user, is refused the namespace sandbox, falls back to the SUID helper, and finds it unconfigured. The right question asked of the wrong user. Replace the postinst and postrm. The postinst installs an AppArmor profile granting the binary `userns create`, which restores the namespace sandbox — the one upstream Chromium develops against, rather than the compatibility helper — and decides the SUID fallback by probing as `nobody` instead of as root. Both scripts re-implement the stock update-alternatives, mime and desktop-database steps, because naming afterInstall/afterRemove replaces those templates rather than extending them. The AppImage cannot be fixed from inside the artifact: a FUSE squashfs mount is nosuid, so the SUID helper can never work from one, and there is no install step in which to place a profile. Documented in the README with a profile users can install, and `--no-sandbox` noted as the worse option it is. Verified: both scripts pass `bash -n` before and after macro expansion, carry no macro the replacer would reject, and both AppArmor profiles parse under the system apparmor_parser. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| abi <abi/4.0>, | ||
| include <tunables/global> | ||
|
|
||
| profile threatcrush-appimage "/tmp/.mount_*/threatcrush-desktop" flags=(unconfined) { |
ThreatCrush Security Scan70 finding(s) HIGH/CRITICAL: 12 | MEDIUM: 57 | LOW: 1
…and 20 more. Full results in the Security tab. Snippets are redacted; ThreatCrush never prints matched credential material. |
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.
Reported from a 26.04 box, on the
.deband the AppImage alike:Cause
electron-builder's stock postinst picks between Chromium's two sandboxes like this:
A postinst runs as root. Ubuntu 24.04+'s
kernel.apparmor_restrict_unprivileged_userns=1restricts unprivileged user namespaces — root is exempt. So the probe succeeds
at install time, the
elsebranch runs, andchrome-sandboxis installed0755.The app is then launched by an ordinary user, refused the namespace sandbox, falls
back to the SUID helper, and finds it unconfigured. The right question asked of the
wrong user.
Fix
resources/after-install.shreplaces the postinst and:userns create, restoring thenamespace sandbox — the one upstream Chromium develops against, rather than
the compatibility helper. This is what Chrome/Chromium settled on for the same
regression.
nobodyrather than as root, so theanswer reflects the conditions the app actually runs under. Unresolvable probe
means "assume SUID is needed" — an unused sandbox costs nothing, a missing one
aborts the app.
resources/after-remove.shunloads and removes the profile. Both re-implement thestock update-alternatives / mime / desktop-database steps, because naming
afterInstall/afterRemovereplaces electron-builder's templates rather thanextending them — flagged in a comment in both files and in
electron-builder.yml.AppImage
Not fixable from inside the artifact, and the README now says so plainly: an
AppImage is a FUSE squashfs mount, FUSE mounts are
nosuid, so the SUID helper cannever work from one whatever its mode bits say — and there is no install step in
which to place a profile. The README gives users a profile to install, and notes
--no-sandboxas the worse option it is (turning the renderer sandbox off in asecurity product is a poor default).
Verification
bash -non both scripts, before and after macro expansion.writeConfigFilesubstitution — it throws on anyundefined
${...}, and these use only${executable}and${sanitizedProductName},the two the stock templates already use.
apparmor_parser -Q -d.chrome-sandbox: unresolvable probe →4755.Not verified end-to-end on a machine that reproduces the abort — this dev box allows
unprivileged userns, so it does not fail in the first place. The one-line confirmation
on an affected box is
ls -l /opt/ThreatCrush/chrome-sandbox:-rwxr-xr-xis the bug,-rwsr-xr-xis the fix.🤖 Generated with Claude Code