Files
podman/pkg/domain/infra/abi/play_utils.go
Paul Holzinger 2ef1cd7f7e [v5.4-rhel] kube play: don't follow volume symlinks onto the host
For ConfigMap and Secret kube play volumes podman populates the data
from the yaml. However the volume content is not controlled by us and we
can be tricked following a symlink to a file on the host instead.

Fixes: CVE-2025-9566

Fixes: https://issues.redhat.com/browse/RHEL-113141,
https://issues.redhat.com/browse/RHEL-113152,
https://issues.redhat.com/browse/OCPBUGS-61268,
https://issues.redhat.com/browse/OCPBUGS-61270

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
Signed-off-by: tomsweeneyredhat <tsweeney@redhat.com>
2025-09-08 18:05:00 -04:00

56 lines
1.8 KiB
Go

//go:build !remote
package abi
import (
"fmt"
"os"
"strings"
"github.com/containers/podman/v5/libpod/define"
"golang.org/x/sys/unix"
)
// getSdNotifyMode returns the `sdNotifyAnnotation/$name` for the specified
// name. If name is empty, it'll only look for `sdNotifyAnnotation`.
func getSdNotifyMode(annotations map[string]string, name string) (string, error) {
var mode string
switch len(name) {
case 0:
mode = annotations[sdNotifyAnnotation]
default:
mode = annotations[sdNotifyAnnotation+"/"+name]
}
return mode, define.ValidateSdNotifyMode(mode)
}
// openPathSafely opens the given name under the trusted root path, the unsafeName
// must be a single path component and not contain "/".
// The resulting path will be opened or created if it does not exists.
// Following of symlink is done within staying under root, escapes outsides
// of root are not allowed and prevent.
//
// This custom function is needed because securejoin.SecureJoin() is not race safe
// and the volume might be mounted in another container that could swap in a symlink
// after the function ahs run. securejoin.OpenInRoot() doesn't work either because
// it cannot create files and doesn't work on freebsd.
func openPathSafely(root, unsafeName string) (*os.File, error) {
if strings.Contains(unsafeName, "/") {
return nil, fmt.Errorf("name %q must not contain path separator", unsafeName)
}
fdDir, err := os.OpenFile(root, unix.O_RDONLY, 0)
if err != nil {
return nil, err
}
defer fdDir.Close()
flags := unix.O_CREAT | unix.O_WRONLY | unix.O_TRUNC | unix.O_CLOEXEC
fd, err := unix.Openat(int(fdDir.Fd()), unsafeName, flags|unix.O_NOFOLLOW, 0o644)
if err == nil {
return os.NewFile(uintptr(fd), unsafeName), nil
}
if err == unix.ELOOP {
return openSymlinkPath(fdDir, unsafeName, flags)
}
return nil, &os.PathError{Op: "openat", Path: unsafeName, Err: err}
}