Skip to content

Windows: os.MkdirTemp resolves to inaccessible C:\Windows\SystemTemp when running as SYSTEM on Go 1.21+ #6591

@doctorpangloss

Description

@doctorpangloss

Bug description

os.MkdirTemp("", "buildkit-mount") in snapshot/localmounter_windows.go resolves to C:\Windows\SystemTemp when buildkitd runs as SYSTEM on Go 1.21+. Go 1.21 introduced GetTempPath2 which returns C:\Windows\SystemTemp for SYSTEM accounts instead of C:\Windows\Temp. This path is inaccessible to the buildkitd process, causing all mounts to fail.

Reproduction

Run buildkitd as SYSTEM (e.g. as a Windows service or HostProcess container). Any build fails:

```
failed to mount ...: failed to create temp dir: mkdir C:\Windows\SystemTemp\buildkit-mount1234: Access is denied.
```

Root cause

Go 1.21+ changed os.TempDir() on Windows to call GetTempPath2W instead of GetTempPathW. For the SYSTEM account, GetTempPath2W returns C:\Windows\SystemTemp rather than C:\Windows\Temp. C:\Windows\SystemTemp is ACL'd to deny access to most processes including SYSTEM itself in common configurations.

snapshot/localmounter_windows.go calls os.MkdirTemp("", "buildkit-mount") with an empty dir argument, which resolves via os.TempDir().

Proposed fix

Use {root}/tmp as the temp directory, where root is the buildkitd --root flag value. This keeps temp mounts under the same root directory that buildkitd already manages and has write access to.

```diff
--- a/snapshot/localmounter.go
+++ b/snapshot/localmounter.go
@@ -2,9 +2,23 @@ package snapshot
import (

  • "os"
  • "path/filepath"
    "sync"
    "github.com/containerd/containerd/v2/core/mount"
    )

+var mountTempDir string
+
+func SetMountTempDir(root string) error {

  • dir := filepath.Join(root, "tmp")
  • if err := os.MkdirAll(dir, 0o700); err != nil {
  •   return err
    
  • }
  • mountTempDir = dir
  • return nil
    +}

--- a/snapshot/localmounter_windows.go
+++ b/snapshot/localmounter_windows.go
@@ -39 +39 @@

  • dir, err := os.MkdirTemp("", "buildkit-mount")
  • dir, err := os.MkdirTemp(mountTempDir, "buildkit-mount")

--- a/cmd/buildkitd/main.go (after os.MkdirAll(root, 0700))
+++ b/cmd/buildkitd/main.go

  • if err := snapshot.SetMountTempDir(root); err != nil {
  •   return errors.Wrapf(err, "failed to set mount temp dir under %s", root)
    
  • }
    ```

Workaround

Run buildkitd as a native Windows service (via --register-service) rather than directly. Windows services running as SYSTEM use GetTempPathW (not GetTempPath2W), so they get C:\Windows\Temp which is accessible.

Version information

```
buildkitd v0.28.0
Go 1.21+
Windows Server 2022 build 20348.4773
Kubernetes v1.34.2+k0s
```

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions