Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions bin/omarchy-windows-vm
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ priv() {

dc() { docker-compose -f "$COMPOSE_FILE" "$@"; }

# chmod preserves a directory's set-user-ID and set-group-ID bits when it is
# given an octal mode, so `chmod 0700 dir` leaves a setgid directory at 2700 and
# the exact-mode check before Docker starts then rejects every bring-up. Clear
# the special bits explicitly so the requested mode is the mode that lands.
chmod_exact() {
local mode="$1"
shift
chmod u-s,g-s,o-t -- "$@" && chmod "$mode" -- "$@"
}

with_vm_lock() {
local fd rc=0
if ((EUID == 0)); then
Expand Down Expand Up @@ -264,7 +274,7 @@ prepare_boundary_component() {
install -d -m "$mode" -- "$path" || return 1
fi
fi
chmod "$mode" -- "$path" || return 1
chmod_exact "$mode" "$path" || return 1
if ((EUID == 0)); then chown root:root -- "$path" || return 1; fi
assert_boundary_dir "$path" "$owner"
}
Expand Down Expand Up @@ -580,7 +590,7 @@ prepare_caller_mounts() {
# Privacy is an explicit preflight step for both already-pinned sources, not
# a side effect halfway through the two-mount transaction. Old umask-022
# installs are hardened together before either Docker-facing anchor changes.
chmod 0700 -- "/proc/$BASHPID/fd/$storage_fd" "/proc/$BASHPID/fd/$shared_fd" || {
chmod_exact 0700 "/proc/$BASHPID/fd/$storage_fd" "/proc/$BASHPID/fd/$shared_fd" || {
exec {storage_fd}<&-
exec {shared_fd}<&-
return 1
Expand Down Expand Up @@ -1015,7 +1025,7 @@ prepare_user_mount_sources() {
echo "omarchy-windows-vm: storage and shared must be different directories" >&2
return 1
}
chmod 0700 -- "$storage" "$shared"
chmod_exact 0700 "$storage" "$shared"
}

storage_space_path() {
Expand Down Expand Up @@ -1058,7 +1068,7 @@ write_credentials() {
local username="$1" password="$2" old_umask dir tmp
dir=$(dirname -- "$CREDENTIALS_FILE")
mkdir -p "$dir" || return 1
chmod 0700 "$dir" || return 1
chmod_exact 0700 "$dir" || return 1
old_umask=$(umask)
umask 077
tmp=$(mktemp "$dir/.credentials.XXXXXX") || { umask "$old_umask"; return 1; }
Expand Down
11 changes: 11 additions & 0 deletions test/shell.d/windows-vm-compose-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,14 @@ df() {
unset -f df
[[ $(cat "$df_log") == "$external_storage" ]] || fail "free-space used home filesystem"
pass "disk-space checks follow the storage symlink target"

# An install whose sources picked up a setgid bit must be normalized, not left
# at 2700: the privileged bring-up compares the mode against 700 exactly, so a
# source chmod that silently keeps the bit locks the VM out for good.
reset_case
mkdir -p "$HOME/.windows" "$HOME/Windows"
chmod 2755 "$HOME/.windows" "$HOME/Windows"
prepare_user_mount_sources || fail "setgid sources were rejected instead of hardened"
[[ $(stat -Lc '%a' "$HOME/.windows") == 700 && $(stat -Lc '%a' "$HOME/Windows") == 700 ]] ||
fail "setgid sources were not hardened to an exact 0700"
pass "setgid mount sources are hardened to an exact 0700"
4 changes: 4 additions & 0 deletions test/shell.d/windows-vm-mount-boundary-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,13 @@ pass "root dispatch rejects missing/invalid uid, passwd, owner, symlink, and wri

# Put each familiar source on its own filesystem. Both start with legacy 0755
# permissions and world-readable payloads to prove migration hardens the leaves.
# The setgid bit is part of that legacy state: chmod keeps a directory's
# set-group-ID bit when it is handed an octal mode, so a source left at 2755
# stays at 2700 and the exact-mode check below rejects every bring-up.
mkdir /home/storage-target /home/shared-target
mount -t tmpfs -o uid=1000,gid=1000,mode=0755,size=3g storage-test /home/storage-target
mount -t tmpfs -o uid=1000,gid=1000,mode=0755,size=64m shared-test /home/shared-target
chmod g+s /home/storage-target /home/shared-target
ln -s /home/storage-target /home/alice/.windows
ln -s /home/shared-target /home/alice/Windows
chown -h 1000:1000 /home/alice/.windows /home/alice/Windows
Expand Down