From f66f555ad48c08c60916c6f57942ef4a609c94f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Mon, 1 Sep 2025 13:28:24 +0200 Subject: [PATCH] graphdriver/windows: Potential fix for access denied MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use `winio.RunWithPrivileges` to get the privileges. It's better because it also locks the Go runtime thread so if the Go scheduler decides to run this code on a different thread, it will still have the expected privileges. A naive attempt at fixing an error experienced by Docker Desktop user when using Windows containers: ``` failed to register layer: re-exec error: exit status 1: output: hcsshim::ProcessUtilityVMImage \\?\C:\ProgramData\Docker\windowsfilter\\UtilityVM: Access is denied. failed to register layer: re-exec error: exit status 1: output: hcsshim::ProcessBaseLayer \\?\C:\ProgramData\Docker\windowsfilter\: Access is denied. failed to register layer: re-exec error: exit status 1: output: hcsshim::ProcessBaseLayer \\?\C:\ProgramData\Docker\windowsfilter\: Access is denied. ``` Unfortunately I can't reproduce the issue on a Windows VM, but this definitely won't hurt. At least, I verified that the daemon still works on Windows. Inspired by: https://github.com/containerd/containerd/issues/8206 Signed-off-by: Paweł Gronowski --- daemon/graphdriver/windows/windows.go | 46 ++++++++++----------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/daemon/graphdriver/windows/windows.go b/daemon/graphdriver/windows/windows.go index 40dd11a39b..83b28c87b3 100644 --- a/daemon/graphdriver/windows/windows.go +++ b/daemon/graphdriver/windows/windows.go @@ -799,37 +799,25 @@ func writeLayerReexec() { } // writeLayer writes a layer from a tar file. -func writeLayer(layerData io.Reader, home string, id string, parentLayerPaths ...string) (size int64, retErr error) { - err := winio.EnableProcessPrivileges([]string{winio.SeSecurityPrivilege, winio.SeBackupPrivilege, winio.SeRestorePrivilege}) - if err != nil { - return 0, err - } - if noreexec { - defer func() { - if err := winio.DisableProcessPrivileges([]string{winio.SeSecurityPrivilege, winio.SeBackupPrivilege, winio.SeRestorePrivilege}); err != nil { - // This should never happen, but just in case when in debugging mode. - // See https://github.com/moby/moby/pull/28002#discussion_r86259241 for rationale. - panic("Failed to disabled process privileges while in non re-exec mode") - } - }() - } - - w, err := hcsshim.NewLayerWriter(hcsshim.DriverInfo{Flavour: filterDriver, HomeDir: home}, id, parentLayerPaths) - if err != nil { - return 0, err - } - - defer func() { - if err := w.Close(); err != nil { - // This error should not be discarded as a failure here - // could result in an invalid layer on disk - if retErr == nil { - retErr = err - } +func writeLayer(layerData io.Reader, home string, id string, parentLayerPaths ...string) (size int64, _ error) { + err := winio.RunWithPrivileges([]string{winio.SeSecurityPrivilege, winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() error { + var err error + w, err := hcsshim.NewLayerWriter(hcsshim.DriverInfo{Flavour: filterDriver, HomeDir: home}, id, parentLayerPaths) + if err != nil { + return err } - }() - return writeLayerFromTar(layerData, w, filepath.Join(home, id)) + s, err := writeLayerFromTar(layerData, w, filepath.Join(home, id)) + if err != nil { + // Close, but don't override the error from writeLayerFromTar + _ = w.Close() + return err + } + + size = s + return w.Close() + }) + return size, err } // resolveID computes the layerID information based on the given id.