Skip to content

fix(security): restrict Windows private files with fail-safe ACL ordering - #164

Open
raymondginger2018-sudo wants to merge 1 commit into
HKUDS:mainfrom
raymondginger2018-sudo:fix/win-private-acl-safe-order
Open

fix(security): restrict Windows private files with fail-safe ACL ordering#164
raymondginger2018-sudo wants to merge 1 commit into
HKUDS:mainfrom
raymondginger2018-sudo:fix/win-private-acl-safe-order

Conversation

@raymondginger2018-sudo

Copy link
Copy Markdown
Contributor

Summary

Redoes the Windows private-file ACL restriction from #148 in a fail-safe order, addressing the exact regression that forced the revert in #158.

Why #148 was reverted (#158)

The original _restrict_windows_acl() ran:

  1. icacls <path> /inheritance:r (strip inherited ACEs)
  2. icacls <path> /grant:r <user>:F (grant the current user)

If the grant failed (service account, transient timeout, ...), the path had already lost every inherited ACE and had no usable ACE for the current user — the file became unopenable, surfacing as sqlite3.OperationalError: attempt to write a readonly database on the Windows lifecycle CI job.

This fix — grant first, strip second, fail safe

_restrict_windows_acl() now:

  1. Grants the current user full control first: icacls <path> /grant:r <user>:F
  2. Only if the grant succeeds, strips inherited ACEs: icacls <path> /inheritance:r
  3. Grant fails → return, leaving the inherited ACLs untouched; the path stays accessible.
  4. Strip fails → the path is merely less restricted, still fully usable.

The identity is resolved via whoami (mbcs encoding, errors="replace"), same as the original PR.

Wiring

_restrict_windows_acl() is applied at every private-storage entry point on Windows:

  • open_private_file() — Windows branch calls _restrict_windows_acl(target) instead of no-op
  • harden_private_tree() — removed the if os.name == "nt": return base early exit so the tree walk repairs ACLs too
  • _chmod() — Windows branch calls _restrict_windows_acl(path) instead of returning early

Tests

New tests/test_private_storage_windows.py (Windows-only, skipped elsewhere) asserts:

  • Dangerous well-known ACEs (Everyone, Authenticated Users, BUILTIN\Users) are removed after restriction
  • The current user retains Full Control (F) after restriction
  • Covers private directories, private files, and full tree hardening

Verified locally on Windows (3 passed) and POSIX suite unaffected (8 skipped as expected).

References

…ring

PR HKUDS#148 introduced Windows ACL restriction for private storage paths, but
ran icacls /inheritance:r before /grant:r. If the grant failed (service
account, transient timeout, ...), the path was left with inherited ACEs
stripped and no usable ACE for the current user, making it unopenable
(e.g. 'attempt to write a readonly database' on Windows CI). HKUDS#158 reverted
the original change for this reason.

Redo the restriction in a fail-safe order:
  1. grant the current user full control first (icacls /grant:r);
  2. only then strip inherited ACEs (icacls /inheritance:r);
  3. if the grant fails, leave inherited ACLs untouched so the path stays
     accessible; if the strip fails, the path is merely less restricted.

Wire the restriction into open_private_file, harden_private_tree and
_chmod so every private-storage entry point applies it on Windows, and
add Windows-only tests asserting dangerous well-known ACEs are removed
while the current user retains full control.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants