Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-617GitHub issuePublicDecided· Out of scope

Windows VM: existing data.img deleted on next start if VM was never cleanly stopped; launcher permission check fails on setgid shared folder

Reported by mladenmir · filed Sep 13, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

Windows VM: existing data.img deleted on next start if VM was never cleanly stopped; launcher permission check fails on setgid shared folderrevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

Omarchy 4.0.3-1, kernel 7.2.3-arch1-3, Docker 29.7.2 + KVM

What's wrong?

Summary

While using Omarchy's built-in Windows VM, I hit two separate but related defects:

  1. Data loss (dockurr/windows lifecycle, as used by Omarchy): if the VM container is never stopped cleanly after installation, dockurr/windows never writes its install-completion marker. On the next start it treats the existing, non-empty data.img as an unfinished installation, deletes it, and starts a fresh unattended Windows install. There is no prompt and no backup.
  2. Launcher permission check (omarchy-windows-vm): after the container's first start, the shared folder carries the setgid bit. The launcher's chmod 0700 keeps that bit, its exact mode == 700 check fails, and the launcher exits silently.

In my case these two combined: issue 2 blocked every start after a host reboot, and the first start after I worked around it triggered issue 1.

The root cause of issue 1 is in dockurr/windows code; I am filing here because the user-facing integration and lifecycle are Omarchy's, and Omarchy could add safeguards. It may need to be forwarded upstream.

Everything below comes from a real incident, logs and file timestamps, and read-only inspection of the exact code that was running (scripts copied from the running container). I did not intentionally reproduce the data loss.

Environment

  • Omarchy 4.0.3-1 (package), omarchy-windows-vm from that package
  • Docker 29.7.2, docker-compose 5.5.1, KVM
  • Image as written by omarchy-windows-vm install: dockurr/windows (no tag/digest pin → resolved to latest)
  • org.opencontainers.image.version: 6.05
  • org.opencontainers.image.revision: efe47da76d49c9d77c0a26799c70315fa4d91055
  • image ID / repo digest: sha256:0cff9eb0e7aee9953e55bc682852ca4fdca233145a58ae1ec94f0b0c01a2ed30
  • Installer defaults: VERSION=11, 4G RAM, 2 cores, 64G disk; storage ~/.windows, shared ~/Windows
  • Host filesystem: Btrfs

Sequence of events

  1. omarchy-windows-vm install created and started the container. Windows 11 was downloaded and installed unattended. The firmware log shows Windows Boot Manager started from the virtual hard disk twice (about 7 and 10 minutes after first boot).
  2. The container kept running and was never stopped. Its on-disk state afterwards still showed running, with no finish time.
  3. Roughly 20 minutes later the host froze for an unknown reason and had to be powered off. I am not attributing the freeze to Omarchy or dockurr/windows.
  4. After reboot, the storage directory contained data.img (read-only check: Windows GPT layout with EFI/MSR/NTFS/recovery partitions, NTFS system volume not dirty) and the old setup.img, but no `windows.boot`.
  5. Launching "Windows" from the menu failed silently; Docker was never even started (issue 2).
  6. I cleared the setgid bit on ~/Windows and ran the privileged start action omarchy-windows-vm __priv up, which runs the same mount/permission preflight. The preflight passed.
  7. On that start the container logged:
   Creating overlay image...
   Adding win11x64.xml for automatic installation...
   Creating a 64 GB growable disk image in raw format...
   BdsDxe: skipped Boot0003 "UEFI QEMU QEMU HARDDISK" ...
   BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM ..."

The new data.img has a file birth time 1.9 s after the container's `StartedAt`, matching that log line to the millisecond. The previous image was gone, and all windows.*, .rom and .vars state files had been recreated (only the ISO was kept). A fresh unattended installation started.
8. After this start ~/Windows was mode 2777 again.

The lost VM was a fresh test installation with no important data, but the same mechanism would destroy a VM that has real data.

Issue 1: an existing disk is deleted when the completion marker was never written

Code is from dockurr/windows 6.05 (/run/*.sh in the running container).

Install decision (install.sh, needsInstall):

if [ -n "$previousBase" ] && [[ "${STORAGE,,}/${previousBase,,}" != "${iso,,}" ]]; then
  ...
  return 0
fi
if [ -n "$previousBase" ] && hasSystemImage; then
  return 1
fi
hasData && hasBootMarker && return 1
return 0
  • hasBootMarker checks $STORAGE/windows.boot.
  • hasData is true when the first 100 KiB of the disk are non-zero.
  • So a non-empty disk without the marker means "install".

Deletion (install.sh): startInstall unconditionally calls cleanupStorage, which runs:

find "$STORAGE" -maxdepth 1 -type f -iname 'data.*' -not -iname '*.iso' -delete

In this incident windows.base matched the current install source (win11x64.iso), so the backup/discard branches of cleanupInstall did not apply, and the deletion came from cleanupStorage. For context:

  • discardPrevious also deletes data.* when the install source changed, or when windows.base is missing, and hasCompletedInstall is false.
  • backupPrevious is used only when hasCompletedInstall is true.

Marker creation (power.sh):

  • markWindowsBooted() is the only place that creates windows.boot.
  • It is called only from finish(), which runs when the container is shut down (the SIGTERM/SIGHUP/SIGABRT/SIGQUIT trap → gracefulShutdown → finish) or when QEMU exits.
  • Even then it writes the marker only if ready() confirms that the last firmware boot entry was Windows Boot Manager from the hard disk, and the install ISO still exists.
  • No path writes the marker while the VM is running.

Consequence: a VM that was installed but never cleanly stopped has no marker. Any interruption that bypasses finish() (host crash, power loss, SIGKILL, OOM kill) makes the next start delete the installed disk and reinstall, with no confirmation and no backup.

Steps to reproduce

Derived from the code; not executed. Use a disposable VM only.

  1. omarchy-windows-vm install and wait until Windows is fully installed.
  2. Do not stop the VM. Interrupt it uncleanly, e.g. docker kill --signal KILL omarchy-windows (or power off the host).
  3. Confirm the storage dir has a non-empty data.img and no windows.boot.
  4. Start again (omarchy-windows-vm __priv up, or launch once issue 2 is worked around).

Expected per code: "Creating a 64 GB growable disk image…", the previous data.img is deleted, and a fresh install starts.

Possible workaround

From the code; not verified by me: after the first installation, stop the VM once with omarchy-windows-vm stop, then confirm that windows.boot exists in the storage directory before relying on the VM.

Suggested safeguards

  • dockurr/windows:
  • never auto-delete a non-empty data.* just because the marker is missing — abort, or rename it to a backup name first;
  • write the marker at runtime as soon as ready() confirms a boot from the installed disk.
  • Omarchy:
  • before up, refuse to start (or back up the disk) when data.* is non-empty but windows.boot is missing;
  • after install, guide the user through one clean stop;
  • document the risk;
  • consider pinning the image digest;
  • forward the lifecycle part upstream.

Issue 2: launcher permission check fails on a setgid shared folder

omarchy-windows-vm, prepare_caller_mounts (runs as root on every up / up_wait):

chmod 0700 -- "/proc/$BASHPID/fd/$storage_fd" "/proc/$BASHPID/fd/$shared_fd" || { ...; return 1; }
storage_mode=$(stat -Lc '%a' "/proc/$BASHPID/fd/$storage_fd" 2>/dev/null) || storage_mode=""
shared_mode=$(stat -Lc '%a' "/proc/$BASHPID/fd/$shared_fd" 2>/dev/null) || shared_mode=""
if [[ $storage_mode != 700 || $shared_mode != 700 ]]; then
  ...
  return 1
fi

mounted_leaf_matches also requires $mode == 700.

  • dockurr/windows side: samba.sh (addShare) runs chmod 2777 "$dir" on an empty, writable shared directory, so after a container start ~/Windows is 2777.
  • Why `chmod 0700` is not enough: GNU chmod with an octal mode of four or fewer digits preserves the setuid/setgid bits on directories. 2777 becomes 2700, stat %a returns 2700, and the function returns 1 without any message. Verified on the affected system: chmod 0700 leaves 2700, chmod 00700 yields 700.
  • Result: after the container's first start, every later launch / up_wait fails while the shared folder is empty. From the menu (Terminal=false) the user gets no diagnostic beyond the generic "Failed to start Windows VM" notification.

Suggested fixes

  • Use chmod 00700 (or chmod u=rwx,go=,g-s) where the directory mode is normalized, and/or validate only the access bits ((mode & 0777) == 0700) instead of the exact %a string.
  • Print the specific failing path, the actual mode and the expected mode to stderr, and surface it in the notification.
  • Note that dockurr/windows' 2777 also leaves the shared folder world-writable while the VM runs.

Scope and uncertainty

  • The cause of the host freeze is unknown and not attributed to Omarchy or dockurr/windows.
  • The data loss was not intentionally reproduced. The mechanism comes from the exact code that was running plus the incident timeline; the deletion itself is not logged by dockurr/windows, but the new disk's creation time matches its log line.
  • The lost VM was a recent test install with no important data.

I can provide the sanitized timeline and full code/log excerpts if helpful.

View raw text
### System details

Omarchy 4.0.3-1, kernel 7.2.3-arch1-3, Docker 29.7.2 + KVM

### What's wrong?

## Summary

While using Omarchy's built-in Windows VM, I hit two separate but related defects:

1. **Data loss (dockurr/windows lifecycle, as used by Omarchy):** if the VM container is never stopped cleanly after installation, dockurr/windows never writes its install-completion marker. On the next start it treats the existing, non-empty `data.img` as an unfinished installation, deletes it, and starts a fresh unattended Windows install. There is no prompt and no backup.
2. **Launcher permission check (omarchy-windows-vm):** after the container's first start, the shared folder carries the setgid bit. The launcher's `chmod 0700` keeps that bit, its exact `mode == 700` check fails, and the launcher exits silently.

In my case these two combined: issue 2 blocked every start after a host reboot, and the first start after I worked around it triggered issue 1.

The root cause of issue 1 is in dockurr/windows code; I am filing here because the user-facing integration and lifecycle are Omarchy's, and Omarchy could add safeguards. It may need to be forwarded upstream.

Everything below comes from a real incident, logs and file timestamps, and read-only inspection of the exact code that was running (scripts copied from the running container). I did **not** intentionally reproduce the data loss.

## Environment

- Omarchy `4.0.3-1` (package), `omarchy-windows-vm` from that package
- Docker `29.7.2`, docker-compose `5.5.1`, KVM
- Image as written by `omarchy-windows-vm install`: `dockurr/windows` (no tag/digest pin → resolved to `latest`)
  - `org.opencontainers.image.version`: `6.05`
  - `org.opencontainers.image.revision`: `efe47da76d49c9d77c0a26799c70315fa4d91055`
  - image ID / repo digest: `sha256:0cff9eb0e7aee9953e55bc682852ca4fdca233145a58ae1ec94f0b0c01a2ed30`
- Installer defaults: `VERSION=11`, 4G RAM, 2 cores, 64G disk; storage `~/.windows`, shared `~/Windows`
- Host filesystem: Btrfs

## Sequence of events

1. `omarchy-windows-vm install` created and started the container. Windows 11 was downloaded and installed unattended. The firmware log shows *Windows Boot Manager* started from the virtual hard disk twice (about 7 and 10 minutes after first boot).
2. The container kept running and was never stopped. Its on-disk state afterwards still showed running, with no finish time.
3. Roughly 20 minutes later the host froze for an **unknown** reason and had to be powered off. I am not attributing the freeze to Omarchy or dockurr/windows.
4. After reboot, the storage directory contained `data.img` (read-only check: Windows GPT layout with EFI/MSR/NTFS/recovery partitions, NTFS system volume not dirty) and the old `setup.img`, but **no `windows.boot`**.
5. Launching "Windows" from the menu failed silently; Docker was never even started (issue 2).
6. I cleared the setgid bit on `~/Windows` and ran the privileged start action `omarchy-windows-vm __priv up`, which runs the same mount/permission preflight. The preflight passed.
7. On that start the container logged:
   ```
   Creating overlay image...
   Adding win11x64.xml for automatic installation...
   Creating a 64 GB growable disk image in raw format...
   BdsDxe: skipped Boot0003 "UEFI QEMU QEMU HARDDISK" ...
   BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM ..."
   ```
   The new `data.img` has a file birth time **1.9 s after the container's `StartedAt`**, matching that log line to the millisecond. The previous image was gone, and all `windows.*`, `.rom` and `.vars` state files had been recreated (only the ISO was kept). A fresh unattended installation started.
8. After this start `~/Windows` was mode `2777` again.

The lost VM was a fresh test installation with no important data, but the same mechanism would destroy a VM that has real data.

## Issue 1: an existing disk is deleted when the completion marker was never written

Code is from `dockurr/windows` 6.05 (`/run/*.sh` in the running container).

**Install decision** (`install.sh`, `needsInstall`):

```bash
if [ -n "$previousBase" ] && [[ "${STORAGE,,}/${previousBase,,}" != "${iso,,}" ]]; then
  ...
  return 0
fi
if [ -n "$previousBase" ] && hasSystemImage; then
  return 1
fi
hasData && hasBootMarker && return 1
return 0
```

- `hasBootMarker` checks `$STORAGE/windows.boot`.
- `hasData` is true when the first 100 KiB of the disk are non-zero.
- So a non-empty disk **without** the marker means "install".

**Deletion** (`install.sh`): `startInstall` unconditionally calls `cleanupStorage`, which runs:

```bash
find "$STORAGE" -maxdepth 1 -type f -iname 'data.*' -not -iname '*.iso' -delete
```

In this incident `windows.base` matched the current install source (`win11x64.iso`), so the backup/discard branches of `cleanupInstall` did not apply, and the deletion came from `cleanupStorage`. For context:

- `discardPrevious` also deletes `data.*` when the install source changed, or when `windows.base` is missing, and `hasCompletedInstall` is false.
- `backupPrevious` is used only when `hasCompletedInstall` is true.

**Marker creation** (`power.sh`):

- `markWindowsBooted()` is the only place that creates `windows.boot`.
- It is called **only** from `finish()`, which runs when the container is shut down (the SIGTERM/SIGHUP/SIGABRT/SIGQUIT trap → `gracefulShutdown` → `finish`) or when QEMU exits.
- Even then it writes the marker only if `ready()` confirms that the last firmware boot entry was *Windows Boot Manager* from the hard disk, and the install ISO still exists.
- No path writes the marker while the VM is running.

**Consequence:** a VM that was installed but never cleanly stopped has no marker. Any interruption that bypasses `finish()` (host crash, power loss, SIGKILL, OOM kill) makes the next start delete the installed disk and reinstall, with no confirmation and no backup.

### Steps to reproduce

Derived from the code; **not executed**. Use a disposable VM only.

1. `omarchy-windows-vm install` and wait until Windows is fully installed.
2. Do not stop the VM. Interrupt it uncleanly, e.g. `docker kill --signal KILL omarchy-windows` (or power off the host).
3. Confirm the storage dir has a non-empty `data.img` and no `windows.boot`.
4. Start again (`omarchy-windows-vm __priv up`, or `launch` once issue 2 is worked around).

Expected per code: "Creating a 64 GB growable disk image…", the previous `data.img` is deleted, and a fresh install starts.

### Possible workaround

From the code; not verified by me: after the first installation, stop the VM once with `omarchy-windows-vm stop`, then confirm that `windows.boot` exists in the storage directory before relying on the VM.

### Suggested safeguards

- **dockurr/windows:**
  - never auto-delete a non-empty `data.*` just because the marker is missing — abort, or rename it to a backup name first;
  - write the marker at runtime as soon as `ready()` confirms a boot from the installed disk.
- **Omarchy:**
  - before `up`, refuse to start (or back up the disk) when `data.*` is non-empty but `windows.boot` is missing;
  - after install, guide the user through one clean stop;
  - document the risk;
  - consider pinning the image digest;
  - forward the lifecycle part upstream.

## Issue 2: launcher permission check fails on a setgid shared folder

`omarchy-windows-vm`, `prepare_caller_mounts` (runs as root on every `up` / `up_wait`):

```bash
chmod 0700 -- "/proc/$BASHPID/fd/$storage_fd" "/proc/$BASHPID/fd/$shared_fd" || { ...; return 1; }
storage_mode=$(stat -Lc '%a' "/proc/$BASHPID/fd/$storage_fd" 2>/dev/null) || storage_mode=""
shared_mode=$(stat -Lc '%a' "/proc/$BASHPID/fd/$shared_fd" 2>/dev/null) || shared_mode=""
if [[ $storage_mode != 700 || $shared_mode != 700 ]]; then
  ...
  return 1
fi
```

`mounted_leaf_matches` also requires `$mode == 700`.

- **dockurr/windows side:** `samba.sh` (`addShare`) runs `chmod 2777 "$dir"` on an empty, writable shared directory, so after a container start `~/Windows` is `2777`.
- **Why `chmod 0700` is not enough:** GNU `chmod` with an octal mode of four or fewer digits **preserves the setuid/setgid bits on directories**. `2777` becomes `2700`, `stat %a` returns `2700`, and the function returns 1 **without any message**. Verified on the affected system: `chmod 0700` leaves `2700`, `chmod 00700` yields `700`.
- **Result:** after the container's first start, every later `launch` / `up_wait` fails while the shared folder is empty. From the menu (`Terminal=false`) the user gets no diagnostic beyond the generic "Failed to start Windows VM" notification.

### Suggested fixes

- Use `chmod 00700` (or `chmod u=rwx,go=,g-s`) where the directory mode is normalized, and/or validate only the access bits (`(mode & 0777) == 0700`) instead of the exact `%a` string.
- Print the specific failing path, the actual mode and the expected mode to stderr, and surface it in the notification.
- Note that dockurr/windows' `2777` also leaves the shared folder world-writable while the VM runs.

## Scope and uncertainty

- The cause of the host freeze is unknown and not attributed to Omarchy or dockurr/windows.
- The data loss was not intentionally reproduced. The mechanism comes from the exact code that was running plus the incident timeline; the deletion itself is not logged by dockurr/windows, but the new disk's creation time matches its log line.
- The lost VM was a recent test install with no important data.

I can provide the sanitized timeline and full code/log excerpts if helpful.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

  • Related PRpr/12155· confirmed

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 12:27 UTC