Safer use of filepath.EvalSymlinks() on Windows

The behavior of function `path/filepath.EvalSymlinks()` has
changed in Go v1.23:

- https://go-review.googlesource.com/c/go/+/565136
- https://go.dev/doc/go1.23#minor_library_changes
- https://tip.golang.org/doc/godebug

As a consequences, starting with Podman 5.3.0, when installing
on Windows (WSL) using scoop, Podman fails to start because it
fails to find helper binaries. Scoop copies Podman binaries in
a folder of type Junction and `EvalSymlinks` returns an error.
The problem is described in #24557.

To address this problem we are checking if a path is a `Symlink`
before calling `EvalSymlinks` and, if it's not (hardlinks, mount
points or canonical files), we are calling `path/filepath.Clean`
for consistency. In fact `path/filepath.EvalSymlinks`, after
evaluating a symlink target, calls `Clean` too.

Signed-off-by: Mario Loriedo <mario.loriedo@gmail.com>
This commit is contained in:
Mario Loriedo
2025-01-28 19:09:06 +01:00
parent eea2866a09
commit 513b4aaceb
2 changed files with 139 additions and 1 deletions

View File

@ -251,7 +251,7 @@ func FindExecutablePeer(name string) (string, error) {
return "", err
}
exe, err = filepath.EvalSymlinks(exe)
exe, err = EvalSymlinksOrClean(exe)
if err != nil {
return "", err
}
@ -259,6 +259,28 @@ func FindExecutablePeer(name string) (string, error) {
return filepath.Join(filepath.Dir(exe), name), nil
}
func EvalSymlinksOrClean(filePath string) (string, error) {
fileInfo, err := os.Lstat(filePath)
if err != nil {
return "", err
}
if fileInfo.Mode()&fs.ModeSymlink != 0 {
// Only call filepath.EvalSymlinks if it is a symlink.
// Starting with v1.23, EvalSymlinks returns an error for mount points.
// See https://go-review.googlesource.com/c/go/+/565136 for reference.
filePath, err = filepath.EvalSymlinks(filePath)
if err != nil {
return "", err
}
} else {
// Call filepath.Clean when filePath is not a symlink. That's for
// consistency with the symlink case (filepath.EvalSymlinks calls
// Clean after evaluating filePath).
filePath = filepath.Clean(filePath)
}
return filePath, nil
}
func GetWinProxyStateDir(name string, vmtype define.VMType) (string, error) {
dir, err := env.GetDataDir(vmtype)
if err != nil {