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

Open
#6,591 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
55/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Tech stack
go

Research direction

Start with snapshot/localmounter_windows.go and trace how the empty directory argument reaches os.MkdirTemp. Then review snapshot/localmounter.go and cmd/buildkitd/main.go around root initialization. Done means Windows builds running as SYSTEM create mount temporary directories under the configured root and mounts no longer fail because of C:\Windows\SystemTemp access errors.

Written by the indexing model from the issue text.

Description

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
```

Dominant language
Go
Stars
10.3k
Forks
1.5k
Avg merge
1d 23h
Merged PRs (30d)
48

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from moby/buildkit

All issues in moby/buildkit

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.