mirror of
https://github.com/containers/podman.git
synced 2025-05-22 09:36:57 +08:00

Fixes new spotted issues around printf() formats and using os.Setenv() in tests. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
188 lines
4.8 KiB
Go
188 lines
4.8 KiB
Go
//go:build !remote
|
|
|
|
package generate
|
|
|
|
import (
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/containers/common/pkg/config"
|
|
"github.com/containers/podman/v5/libpod/define"
|
|
"github.com/containers/podman/v5/pkg/rootless"
|
|
"github.com/containers/podman/v5/pkg/util"
|
|
"github.com/containers/storage/pkg/fileutils"
|
|
|
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/opencontainers/runtime-tools/generate"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/sys/unix"
|
|
"tags.cncf.io/container-device-interface/pkg/cdi"
|
|
)
|
|
|
|
// DevicesFromPath computes a list of devices
|
|
func DevicesFromPath(g *generate.Generator, devicePath string) error {
|
|
if isCDIDevice(devicePath) {
|
|
registry, err := cdi.NewCache(
|
|
cdi.WithAutoRefresh(false),
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("creating CDI registry: %w", err)
|
|
}
|
|
if err := registry.Refresh(); err != nil {
|
|
logrus.Debugf("The following error was triggered when refreshing the CDI registry: %v", err)
|
|
}
|
|
if _, err := registry.InjectDevices(g.Config, devicePath); err != nil {
|
|
return fmt.Errorf("setting up CDI devices: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
devs := strings.Split(devicePath, ":")
|
|
resolvedDevicePath := devs[0]
|
|
// check if it is a symbolic link
|
|
if src, err := os.Lstat(resolvedDevicePath); err == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
|
|
if linkedPathOnHost, err := filepath.EvalSymlinks(resolvedDevicePath); err == nil {
|
|
resolvedDevicePath = linkedPathOnHost
|
|
}
|
|
}
|
|
st, err := os.Stat(resolvedDevicePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if st.IsDir() {
|
|
found := false
|
|
src := resolvedDevicePath
|
|
dest := src
|
|
var devmode string
|
|
if len(devs) > 1 {
|
|
if len(devs[1]) > 0 && devs[1][0] == '/' {
|
|
dest = devs[1]
|
|
} else {
|
|
devmode = devs[1]
|
|
}
|
|
}
|
|
if len(devs) > 2 {
|
|
if devmode != "" {
|
|
return fmt.Errorf("invalid device specification %s: %w", devicePath, unix.EINVAL)
|
|
}
|
|
devmode = devs[2]
|
|
}
|
|
|
|
// mount the internal devices recursively
|
|
if err := filepath.WalkDir(resolvedDevicePath, func(dpath string, d fs.DirEntry, e error) error {
|
|
if d.Type()&os.ModeDevice == os.ModeDevice {
|
|
found = true
|
|
device := fmt.Sprintf("%s:%s", dpath, filepath.Join(dest, strings.TrimPrefix(dpath, src)))
|
|
if devmode != "" {
|
|
device = fmt.Sprintf("%s:%s", device, devmode)
|
|
}
|
|
if err := addDevice(g, device); err != nil {
|
|
return fmt.Errorf("failed to add %s device: %w", dpath, err)
|
|
}
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if !found {
|
|
return fmt.Errorf("no devices found in %s: %w", devicePath, unix.EINVAL)
|
|
}
|
|
return nil
|
|
}
|
|
return addDevice(g, strings.Join(append([]string{resolvedDevicePath}, devs[1:]...), ":"))
|
|
}
|
|
|
|
func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, mask, unmask []string, g *generate.Generator) {
|
|
if !privileged {
|
|
for _, mp := range config.DefaultMaskedPaths {
|
|
// check that the path to mask is not in the list of paths to unmask
|
|
if shouldMask(mp, unmask) {
|
|
g.AddLinuxMaskedPaths(mp)
|
|
}
|
|
}
|
|
for _, rp := range config.DefaultReadOnlyPaths {
|
|
if shouldMask(rp, unmask) {
|
|
g.AddLinuxReadonlyPaths(rp)
|
|
}
|
|
}
|
|
|
|
if pidModeIsHost && rootless.IsRootless() {
|
|
return
|
|
}
|
|
}
|
|
|
|
// mask the paths provided by the user
|
|
for _, mp := range mask {
|
|
if !path.IsAbs(mp) && mp != "" {
|
|
logrus.Errorf("Path %q is not an absolute path, skipping...", mp)
|
|
continue
|
|
}
|
|
g.AddLinuxMaskedPaths(mp)
|
|
}
|
|
}
|
|
|
|
func addDevice(g *generate.Generator, device string) error {
|
|
src, dst, permissions, err := ParseDevice(device)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dev, err := util.DeviceFromPath(src)
|
|
if err != nil {
|
|
return fmt.Errorf("%s is not a valid device: %w", src, err)
|
|
}
|
|
if rootless.IsRootless() {
|
|
if err := fileutils.Exists(src); err != nil {
|
|
return err
|
|
}
|
|
perm := "ro"
|
|
if strings.Contains(permissions, "w") {
|
|
perm = "rw"
|
|
}
|
|
devMnt := spec.Mount{
|
|
Destination: dst,
|
|
Type: define.TypeBind,
|
|
Source: src,
|
|
Options: []string{"slave", "nosuid", "noexec", perm, "rbind"},
|
|
}
|
|
g.Config.Mounts = append(g.Config.Mounts, devMnt)
|
|
return nil
|
|
} else if src == "/dev/fuse" {
|
|
// if the user is asking for fuse inside the container
|
|
// make sure the module is loaded.
|
|
f, err := unix.Open(src, unix.O_RDONLY|unix.O_NONBLOCK, 0)
|
|
if err == nil {
|
|
unix.Close(f)
|
|
}
|
|
}
|
|
dev.Path = dst
|
|
g.AddDevice(*dev)
|
|
g.AddLinuxResourcesDevice(true, dev.Type, &dev.Major, &dev.Minor, permissions)
|
|
return nil
|
|
}
|
|
|
|
func supportAmbientCapabilities() bool {
|
|
err := unix.Prctl(unix.PR_CAP_AMBIENT, unix.PR_CAP_AMBIENT_IS_SET, 0, 0, 0)
|
|
return err == nil
|
|
}
|
|
|
|
func shouldMask(mask string, unmask []string) bool {
|
|
for _, m := range unmask {
|
|
if strings.ToLower(m) == "all" {
|
|
return false
|
|
}
|
|
for _, m1 := range strings.Split(m, ":") {
|
|
match, err := filepath.Match(m1, mask)
|
|
if err != nil {
|
|
logrus.Error(err.Error())
|
|
}
|
|
if match {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|