Skip to content

omarchy-windows-vm: launch fails silently after the first success (setgid re-chmod loop on ~/Windows) #11575

Closed

Description

@ZuluPilgrim

What happened

After the compose file is migrated to the new root-owned location (/var/lib/omarchy/windows/docker-compose.yml), every subsequent omarchy-windows-vm launch/up/up_wait call keeps re-validating and re-chmoding the legacy shared-folder source directory (~/Windows), and that re-validation reliably fails after the first successful launch — with the VM's own critical desktop notification "Failed to start Windows VM" and no diagnostic text printed anywhere (not on the terminal, not in the journal for the launching scope).

Root cause chain, confirmed by tracing with bash -x through pkexec omarchy-windows-vm __priv up_wait:

  1. assert_mounts_safe() unconditionally calls prepare_caller_mounts() on every privileged action when EUID == 0 (i.e. on every up/up_wait, not just the first-time migration):
    if ((EUID == 0)); then
      prepare_caller_mounts || return 1
    fi
    
  2. prepare_caller_mounts() re-opens the legacy source directories (~/.windows, ~/Windows) and requires their mode to read back as exactly 700 after doing chmod 0700 on them:
    chmod 0700 -- "/proc/$BASHPID/fd/$storage_fd" "/proc/$BASHPID/fd/$shared_fd" || { ...; return 1; }
    storage_mode=$(stat -Lc '%a' ...)
    shared_mode=$(stat -Lc '%a' ...)
    if [[ $storage_mode != 700 || $shared_mode != 700 ]]; then
      ...
      return 1
    fi
    
    This branch has no echo on failure — a silent return 1 that bubbles all the way up to "Failed to start Windows VM" with zero explanation.
  3. In my case ~/Windows had (and, more importantly, kept getting) a setgid bit (2700 instead of 0700) — something tied to the running VM's live shared-folder passthrough (this directory is bind-mounted through to the dockurr/windows container as /shared for the whole time the VM runs) keeps re-adding the setgid bit shortly after it's cleared.
  4. chmod 0700 <path> (a 3-significant-digit numeric mode) does not clear a pre-existing setgid bit — only chmod 2700/chmod g-s/symbolic notation does. So the script's own remediation chmod 0700 call in step 2 is a silent no-op against a directory that already has setgid set, and the mode check keeps failing.

Net effect

  • The first launch after migration succeeds (the source dirs happen to be clean at that moment).
  • Every launch after that fails, silently, with only a generic "Failed to start Windows VM" notification — because the always-on re-validation in step 1 keeps re-discovering the setgid bit that something (very likely the VM's own SMB/9p sharing of /shared with the Windows guest) keeps restoring.
  • There is no way for a user to know why it failed short of bash -x-tracing the privileged helper — none of omarchy-windows-vm status, launch, or the desktop notification give any hint.

Expected behavior

  • prepare_caller_mounts's remediation chmod should actually clear pre-existing special bits (e.g. chmod -- 0700 numeric mode doesn't do this — use chmod g-s,u-s,-t or an explicit non-abbreviated form, or just retry with chmod 2700 ... && chmod 0700 ...).
  • More importantly: re-verifying/re-establishing the legacy-source bind mounts on every single launch (even when the compose is already fully migrated and the container/mounts are already up and healthy) seems unnecessary and is what turns a one-off permission quirk into a permanent failure loop. Consider skipping prepare_caller_mounts when the expected protected mounts are already active and healthy (mounts_ready already exists and is checked separately).
  • At minimum, any failure branch that can end in "Failed to start Windows VM" should surface the actual reason (even just to the journal) instead of a bare return 1.

Steps to reproduce

  1. Have an existing Windows VM installed under the older ~/.config/windows/docker-compose.yml layout with a ~/Windows shared-folder directory that has (or acquires) a setgid bit.
  2. Upgrade Omarchy to a version that migrates the compose to /var/lib/omarchy/windows/docker-compose.yml and adds the assert_mounts_safe/prepare_caller_mounts re-validation on every launch.
  3. Launch the Windows VM once — it migrates and starts successfully.
  4. Launch it again while it's still running — it fails with "Failed to start Windows VM" and no further explanation.
  5. chmod g-s ~/Windows and launch again — succeeds. Wait a few minutes while the VM keeps running, launch a third time — fails again, and stat -c '%a' ~/Windows shows 2700 again.

System details

  • Omarchy 4.0.3-1
  • Hyprland 0.56.2-2
  • Docker 29.7.2 / Docker Compose plugin 5.5.1
  • CPU: Intel Xeon E5-1660 v4
  • GPU: NVIDIA GeForce GTX 1080 Ti (nvidia driver)
  • ~ filesystem: btrfs

Activity

  1. Flogrn commented on Sep 13, 2026

    @Flogrn

    Bug: omarchy-windows-vm install fails with "Failed to write the Windows VM configuration" — recurs even after chmod 0700, and even after running omarchy-update.

    Root cause: prepare_caller_mounts() runs chmod 0700 on the storage/shared mount-source file descriptors, then requires the resulting mode to read back as exactly 700. But GNU chmod with a numeric mode doesn't clear a pre-existing setgid bit — chmod 0700 on a 2700 directory leaves it at 2700, so the strict equality check always fails once setgid gets set on the shared folder (e.g. by a prior container run).

    Fix that worked: Manually edited /usr/bin/omarchy-windows-vm, changing the line chmod 0700 -- "/proc/$BASHPID/fd/$storage_fd" "/proc/$BASHPID/fd/$shared_fd" to chmod a-s,u=rwx,go= -- ... instead — explicitly stripping setgid rather than relying on the numeric form. Install and launch worked immediately after.

    I tracked this down with Claude (Anthropic's AI assistant) — walked through bash -x tracing the script step by step until we isolated the exact failing chmod/stat check.

  2. bjarneo commented on Sep 20, 2026

    @bjarneo
    Member

    Automated duplication check: this issue looks similar to #9334, which covers the same Windows VM setgid permission check. I keep that one open and close this one to keep the discussion in one place.

    If you feel this is the wrong decision, please open the issue again with a note on the difference.

  3. omarchybot commented on Oct 4, 2026

    @omarchybot
    Collaborator

    Update: #12323 has merged into quattro. The setgid permission rejection is now fixed in both source-directory hardening paths, with an explicit mode diagnostic. This does not claim that runtime share privacy or every desktop failure notification is fixed.

    Scope checked by GPT-6 in Codex and Codex Medium against the discussion and landed change; review independence is not guaranteed. No tests were rerun for this cleanup.

    Omabot on behalf of DHH

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