Skip to content

sudo and bwrap-based sandboxes (e.g. Codex CLI) break inside a shell spawned by the AppImage - FUSE mount runs in a private user namespace #160

Description

@codemedic

Summary

Any shell (or child process) spawned by the AppImage inherits a private, unprivileged user namespace created during the FUSE/DwarFS self-mount. Tools that check real uid/capability metadata against on-disk ownership - sudo, and sandboxes built on bubblewrap (e.g. Codex CLI) - fail inside that shell, because root (uid 0) isn't mapped in the namespace.

Reproduction

$ ~/Applications/Ghostty-<version>-x86_64.AppImage
# in the resulting shell:
$ sudo apt update
sudo: /etc/sudo.conf is owned by uid 65534, should be 0
sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set

Evidence

  • cat /proc/self/uid_map in the shell: 1000 1000 1 - only uid 1000 is mapped; uid 0 has no mapping, so root-owned files appear as uid 65534 (kernel.overflowuid).
  • Compare to /proc/1/uid_map (init, not namespaced): full range mapped.
  • readlink /proc/<pid>/ns/user is identical across the dwarfs mount process, the ghostty binary, and the login shell - confirming they share one namespace.
  • strace -f -e trace=clone,clone3,unshare,setns on the raw AppImage shows the runtime attempting a pidfd-based setns() (namespace reuse across launches); the fully-extracted binary (--appimage-extract then run AppRun directly) makes zero such calls.
  • /proc/self/status in the shell shows CapEff: 00000000ffffffff - full capabilities despite not being setuid/root, which is what trips bwrap's own sanity check (bwrap: Unexpected capabilities but not setuid, old file caps config?), breaking Codex CLI's sandbox the same way.

Workaround confirmed working

Embedding APPIMAGE_EXTRACT_AND_RUN=1 via --appimage-addenvs avoids the FUSE mount (and thus the namespace) entirely - verified via strace: zero clone/unshare/setns calls, sudo and bwrap both work normally afterward.

Question for you

Given #158 was actually fixed upstream in Anylinux-AppImages rather than here, is this the same situation - i.e. is the unshare/reuse behavior coming from uruntime/quick-sharun rather than anything ghostty-appimage-specific? If so, is baking APPIMAGE_EXTRACT_AND_RUN=1 into the build (or fixing the reuse logic to not require a private namespace) something you'd want done here, upstream, or not at all? Happy to send a PR to bin/bundle-appimage.sh if that's the right place - wanted your read first given the shared-tooling precedent.


Note: written with AI assistance (Claude Code) during a debugging session.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions