Skip to content
  _   _    ____    ___   __        __
 | | | |  / ___|  / _ \  \ \      / /
 | | | | | |  _  | | | |  \ \ /\ / /
 | |_| | | |_| | | |_| |   \ V  V /
  \___/   \____|  \___/     \_/\_/

UGOW

Unix Grant Overlay for Windows drives in WSL2

Fine-grained, per-user write control for /mnt/c, /mnt/d, and beyond.

Get Started View on GitHub


The Problem

WSL2 mounts Windows drives via /mnt/c with effectively wide-open Unix permissions (often 777), but the actual NTFS ACLs underneath don't know or care about Linux UIDs. Linux thinks everything is permitted, Windows disagrees, and there's no unified control plane.

It started with a QA engineer running a Docker container in WSL2, mounting a Windows-native path (C:\Docker) as a volume. The container ran as UID 9500 -- not the default Ubuntu UID 1000. Everything broke. The errors were cryptic. Every fix required changes on the Windows side.

I couldn't find a clean solution, so I built one.

Features

  • Three enforcement backends -- choose FUSE (easiest), BPF LSM (fastest), or a compiled-in kernel module.
  • Multi-drive support -- manage any Windows drive (C:, D:, E:, ...) with a single command.
  • W-bit enforcement -- gates access, open, create, truncate, mkdir, unlink, rmdir, rename, symlink, link, chmod, and utimens. A hard link needs the W-bit on both ends, and setuid/setgid bits can never be set through the shim.
  • Permission inheritance -- a grant on a directory applies to all descendants automatically.
  • Audited denials -- every refused operation is logged with the operation, UID, and path.
  • ACL mirroring -- optionally creates matching NTFS ACL grants via PowerShell/icacls.
  • Unified CLI -- ugow allow, deny, check, status, list, sync, acl-cleanup -- works the same across all backends.

Quick Example

# Install (one command)
sudo ./setup.sh

# Grant a user write access
sudo ugow allow ubuntu /mnt/c/docker

# Check access
sudo ugow check /mnt/c/docker

# Use with Docker -- no special paths needed
docker run --user 9500 -v /mnt/c/userdata:/data my-image

Choose Your Backend

FUSE BPF kmod
Install sudo ./setup.sh sudo ./setup.sh --mode bpf Custom kernel build
Where it runs Userspace Kernel (eBPF) Kernel (compiled-in)
Custom kernel? No No (stock WSL2 6.6+) Yes
Overhead Moderate Near zero Near zero
Bypass resistance Mountpoint only Full Full

Compare backends in detail


Originally: User Group Other Windows -- because that's the Unix permission model this extends. Rebranded to something that sounds like it belongs on a resume.