Windows Version
Microsoft Windows [Version 10.0.26200.9168]
WSL Version
WSL version: 2.7.12.0
Kernel version: 6.18.33.2-2
WSLg version: 1.0.73.2
MSRDC version: 1.2.7214
Direct3D version: 1.611.1-81528511
Are you using WSL 1 or WSL 2?
Kernel Version
6.18.33.2-microsoft-standard-WSL2
Distro Version
Affected: Kali GNU/Linux Rolling 2026.3, systemd 261.2-1, no /etc/wsl.conf (PID 1 is init).
Compared on the same host against Debian 12 (systemd 252.39, init) and Ubuntu (systemd 255.4, [boot] systemd=true).
Other Software
None. This reproduces with stock distro package tooling (apt, dpkg, systemd-tmpfiles).
Repro Steps
On a WSLg-enabled distro that does not boot systemd, with systemd >= 261 installed (at least from what I could find):
sudo systemd-tmpfiles --create x11.conf; echo "exit=$?"
# fchmod() of /tmp/.X11-unix failed: Read-only file system
# exit=73
sudo apt upgrade then fails at Setting up systemd, leaving the dpkg backlog shown below.
The condition is latent rather than absent on Debian 12. It is hidden only by the ! flag. Forcing that flag to be honoured reproduces the identical failure there:
sudo systemd-tmpfiles --create x11.conf; echo "exit=$?" # exit=0
sudo systemd-tmpfiles --create --boot x11.conf; echo "exit=$?" # exit=73, same fchmod error
This suggests the affected population grows substantially once distros pick up systemd >= 261 built with debhelper 14.
Expected Behavior
Installing or upgrading the systemd package on a WSLg-enabled distro should complete successfully, the same way it does on a distro where WSL writes /run/tmpfiles.d/x11.conf.
Actual Behavior
Setting up systemd (261.2-1) ...
fchmod() of /tmp/.X11-unix failed: Read-only file system
dpkg: error processing package systemd (--configure):
old systemd package postinst maintainer script subprocess failed with exit status 73
Errors were encountered while processing:
systemd
Error: Sub-process /usr/bin/dpkg returned an error code (1)
systemd is left half-configured and 19 further packages stall unpacked behind it (exim4-*, gvfs*, lightdm, network-manager, openssh-*, stunnel*, libpam-systemd, systemd-sysv). Every retry reproduces identically; the upgrade cannot proceed without manual intervention.
Diagnostic Logs
Not attached. This reproduces deterministically from the one-line repro above, and the failure is entirely in the guest's package-configure path rather than in WSL's own logging.
Summary
WSL already ships a partial fix for this problem: it writes /run/tmpfiles.d/x11.conf to shadow systemd's vendor rule for /tmp/.X11-unix. However, on a WSL distro that does not boot systemd, that file (on my computer) is never written, nothing shadows the vendor rule, and on current systemd + debhelper the result is no longer a harmless boot warning. It fails package configuration and stalls apt completely.
From what I can tell the two conditions WSL already tests before writing that file (enableGuiApps, and /mnt/wslg/runtime-dir existing) are both satisfied on the affected distros. Only the placement of the write appears to prevent it from happening.
Root cause
WSLg bind-mounts the X11 socket directory into the guest read-only:
$ mount | grep X11
none on /tmp/.X11-unix type tmpfs (ro,relatime)
$ ls -ld /tmp/.X11-unix
drwxrwxrwx 2 root root 60 /tmp/.X11-unix
systemd's /usr/lib/tmpfiles.d/x11.conf declares:
D /tmp/.X11-unix 1777 root root 1h
D creates the directory as well as enforces the stated mode. The directory exists at 0777, the rule requires 1777, so systemd-tmpfiles must fchmod(), and this returns EROFS. systemd-tmpfiles exits 73, and the systemd postinst calls it unconditionally at configure time:
# Automatically added by dh_installtmpfiles/14.3
if [ "$1" = "configure" ] || ... ; then
systemd-tmpfiles ${DPKG_ROOT:+--root="$DPKG_ROOT"} --create ... x11.conf
fi
dpkg sees the non-zero exit and leaves the package half-configured.
Why this is 'new', and why I think it only hits some distros currently
The bug I don't think is truly new. From what I can tell it has existed since WSLg shipped, and what has changed is that it is now fatal, stalls apt and dpkg, instead of being silently swallowed.
I have found three independent things that have historically masked this. If you lose all three then it causes the error. Measured on my local device:
|
Debian 12 |
Ubuntu |
Kali (broken) |
| systemd |
252.39 |
255.4 |
261.2 |
x11.conf rule |
D! (boot-only) |
D! (boot-only) |
D |
| debhelper |
13.11.4 |
13.14.1ubuntu5 |
14.3 |
| postinst guard |
|| true |
|| true |
none |
/run/tmpfiles.d/x11.conf |
absent |
present |
absent |
/mnt/wslg/runtime-dir |
exists |
exists |
exists |
| PID 1 |
init |
systemd |
init |
- The
! flag. D! marks a rule boot-only; systemd-tmpfiles --create skips it unless --boot is given, and the postinst does not pass --boot. Upstream systemd has since dropped the !. The current main reads D /tmp/.X11-unix 1777 root root 1h.
|| true. debhelper 13.x appended it to the generated call; 14.3 does not. Ubuntu's own postinst carries a hand-written comment above its call: "Ignore if this fails, because e.g. %b will fail on WSL."
- WSL's mitigation: The part this report is about.
The specific WSL-side finding
I don't see this occurring on a non-WSL linux machine, since it is tied into how WSLg works. (I quickly looked at the code and I think I may have found part of the problem, but I could be wrong.)
/run/tmpfiles.d/x11.conf contains exactly:
# Note: This file is generated by WSL to prevent systemd-tmpfiles from removing /tmp/.X11-unix during boot.
Being empty of rules, it shadows /usr/lib/tmpfiles.d/x11.conf entirely by tmpfiles.d(5) precedence and neutralises the problem completely. It is present on the Ubuntu instance (systemd enabled) and absent on Kali and Debian (both init), where /run/tmpfiles.d/ does not exist at all.
The obvious explanation, that a precondition isn't met on those distros, does not hold. /mnt/wslg/runtime-dir exists on all three, and GUI apps are working on all three (DISPLAY=:0, live X0 socket). So both conditions WSL tests are already true where the file is missing.
Reading src/linux/init/init.cpp at 4bfbaca, the write appears as:
if (enableGuiApps && access("/mnt/wslg/runtime-dir", F_OK) == 0)
{
THROW_LAST_ERROR_IF(UtilMkdirPath("/run/tmpfiles.d", 0755) < 0);
const std::string tmpFilesConfig =
"# Note: This file is generated by WSL to prevent systemd-tmpfiles from removing /tmp/.X11-unix during boot.\n";
THROW_LAST_ERROR_IF(WriteToFile("/run/tmpfiles.d/x11.conf", tmpFilesConfig.c_str()) < 0);
Which sits inside GenerateSystemdUnits(): a function that would not be expected to run when systemd is not the init system. That would explain the observed behaviour, though I may be misreading the call graph; the empirical results above stand regardless of that detail.
Suggested fix
I have only given a cursory glance at WSL to fix my own local distro, however I would advise that you write /run/tmpfiles.d/x11.conf on every WSLg-enabled distro, not only those booting systemd. The guard conditions already written (enableGuiApps + /mnt/wslg/runtime-dir) appear to express exactly the right intent; only the placement excludes the affected case. The file is inert on a system that never runs systemd-tmpfiles at boot, so writing it unconditionally should carry no cost.
A distro not booting systemd can still have the systemd package installed, and its maintainer scripts still run systemd-tmpfiles at package-configure time, which is the case I think this misses.
Alternatively, mounting /tmp/.X11-unix with mode 1777 would satisfy the rule, instead of violating it, and would additionally address the long-standing _XSERVTransmkdir: Mode of /tmp/.X11-unix should be set to 1777 warnings (#11943).
Workaround
What I did to 'fix' it on my local distro so that I could update my wsl -d kali-linux:
Shadow the vendor rule from /etc, which takes precedence over /usr/lib and survives upgrades. The vendor file is not a dpkg conffile and is restored on every systemd upgrade, so editing it is ineffective:
sudo tee /etc/tmpfiles.d/x11.conf >/dev/null <<'EOF'
D /tmp/.ICE-unix 1777 root root 1h
D /tmp/.XIM-unix 1777 root root 1h
D /tmp/.font-unix 1777 root root 1h
r! /tmp/.X[0-9]*-lock
x /tmp/.X[0-9]*-lock
EOF
sudo dpkg --configure -a
Related
Side note
I do not commonly submit bug reports, so I am sorry if this isn't clear enough. Hopefully I provided enough information to get to the root of the problem.
Windows Version
WSL Version
Are you using WSL 1 or WSL 2?
Kernel Version
6.18.33.2-microsoft-standard-WSL2
Distro Version
Affected: Kali GNU/Linux Rolling 2026.3, systemd 261.2-1, no
/etc/wsl.conf(PID 1 isinit).Compared on the same host against Debian 12 (systemd 252.39,
init) and Ubuntu (systemd 255.4,[boot] systemd=true).Other Software
None. This reproduces with stock distro package tooling (
apt,dpkg,systemd-tmpfiles).Repro Steps
On a WSLg-enabled distro that does not boot systemd, with systemd >= 261 installed (at least from what I could find):
sudo apt upgradethen fails atSetting up systemd, leaving the dpkg backlog shown below.The condition is latent rather than absent on Debian 12. It is hidden only by the
!flag. Forcing that flag to be honoured reproduces the identical failure there:This suggests the affected population grows substantially once distros pick up systemd >= 261 built with debhelper 14.
Expected Behavior
Installing or upgrading the
systemdpackage on a WSLg-enabled distro should complete successfully, the same way it does on a distro where WSL writes/run/tmpfiles.d/x11.conf.Actual Behavior
systemd is left half-configured and 19 further packages stall unpacked behind it (
exim4-*,gvfs*,lightdm,network-manager,openssh-*,stunnel*,libpam-systemd,systemd-sysv). Every retry reproduces identically; the upgrade cannot proceed without manual intervention.Diagnostic Logs
Not attached. This reproduces deterministically from the one-line repro above, and the failure is entirely in the guest's package-configure path rather than in WSL's own logging.
Summary
WSL already ships a partial fix for this problem: it writes
/run/tmpfiles.d/x11.confto shadow systemd's vendor rule for/tmp/.X11-unix. However, on a WSL distro that does not boot systemd, that file (on my computer) is never written, nothing shadows the vendor rule, and on current systemd + debhelper the result is no longer a harmless boot warning. It fails package configuration and stallsaptcompletely.From what I can tell the two conditions WSL already tests before writing that file (
enableGuiApps, and/mnt/wslg/runtime-direxisting) are both satisfied on the affected distros. Only the placement of the write appears to prevent it from happening.Root cause
WSLg bind-mounts the X11 socket directory into the guest read-only:
systemd's
/usr/lib/tmpfiles.d/x11.confdeclares:Dcreates the directory as well as enforces the stated mode. The directory exists at0777, the rule requires1777, sosystemd-tmpfilesmustfchmod(), and this returnsEROFS.systemd-tmpfilesexits 73, and the systemd postinst calls it unconditionally at configure time:dpkg sees the non-zero exit and leaves the package half-configured.
Why this is 'new', and why I think it only hits some distros currently
The bug I don't think is truly new. From what I can tell it has existed since WSLg shipped, and what has changed is that it is now fatal, stalls
aptanddpkg, instead of being silently swallowed.I have found three independent things that have historically masked this. If you lose all three then it causes the error. Measured on my local device:
x11.confruleD!(boot-only)D!(boot-only)D|| true|| true/run/tmpfiles.d/x11.conf/mnt/wslg/runtime-dirinitsystemdinit!flag.D!marks a rule boot-only;systemd-tmpfiles --createskips it unless--bootis given, and the postinst does not pass--boot. Upstream systemd has since dropped the!. The currentmainreadsD /tmp/.X11-unix 1777 root root 1h.|| true. debhelper 13.x appended it to the generated call; 14.3 does not. Ubuntu's own postinst carries a hand-written comment above its call: "Ignore if this fails, because e.g. %b will fail on WSL."The specific WSL-side finding
I don't see this occurring on a non-WSL linux machine, since it is tied into how WSLg works. (I quickly looked at the code and I think I may have found part of the problem, but I could be wrong.)
/run/tmpfiles.d/x11.confcontains exactly:Being empty of rules, it shadows
/usr/lib/tmpfiles.d/x11.confentirely bytmpfiles.d(5)precedence and neutralises the problem completely. It is present on the Ubuntu instance (systemd enabled) and absent on Kali and Debian (bothinit), where/run/tmpfiles.d/does not exist at all.The obvious explanation, that a precondition isn't met on those distros, does not hold.
/mnt/wslg/runtime-direxists on all three, and GUI apps are working on all three (DISPLAY=:0, liveX0socket). So both conditions WSL tests are already true where the file is missing.Reading
src/linux/init/init.cppat 4bfbaca, the write appears as:Which sits inside
GenerateSystemdUnits(): a function that would not be expected to run when systemd is not the init system. That would explain the observed behaviour, though I may be misreading the call graph; the empirical results above stand regardless of that detail.Suggested fix
I have only given a cursory glance at WSL to fix my own local distro, however I would advise that you write
/run/tmpfiles.d/x11.confon every WSLg-enabled distro, not only those booting systemd. The guard conditions already written (enableGuiApps+/mnt/wslg/runtime-dir) appear to express exactly the right intent; only the placement excludes the affected case. The file is inert on a system that never runssystemd-tmpfilesat boot, so writing it unconditionally should carry no cost.A distro not booting systemd can still have the systemd package installed, and its maintainer scripts still run
systemd-tmpfilesat package-configure time, which is the case I think this misses.Alternatively, mounting
/tmp/.X11-unixwith mode1777would satisfy the rule, instead of violating it, and would additionally address the long-standing_XSERVTransmkdir: Mode of /tmp/.X11-unix should be set to 1777warnings (#11943).Workaround
What I did to 'fix' it on my local distro so that I could update my
wsl -d kali-linux:Shadow the vendor rule from
/etc, which takes precedence over/usr/liband survives upgrades. The vendor file is not a dpkg conffile and is restored on every systemd upgrade, so editing it is ineffective:Related
/tmp/.X11-unixmounted read-only (closedbydesign)/tmp/.X11-unixshould be 1777 (closed as duplicate)fchmod()failure reported independently in other ecosystems, each worked around locally:fchmod() of /tmp/.X11-unix failed: Read-only file system nix-community/NixOS-WSL#269, systemd default tmpfiles removes /tmp/.X11-unix/X0 nix-community/NixOS-WSL#114, WSL integration OpenRC/openrc#871
Side note
I do not commonly submit bug reports, so I am sorry if this isn't clear enough. Hopefully I provided enough information to get to the root of the problem.