mirror of
https://github.com/containers/podman.git
synced 2025-07-17 17:43:23 +08:00

These files should never be included on the remote client. There only there to finalize the spec on the server side. This makes sure it will not get reimported by accident and bloat the remote client again. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
204 lines
5.0 KiB
Go
204 lines
5.0 KiB
Go
//go:build !remote
|
|
// +build !remote
|
|
|
|
package generate
|
|
|
|
import (
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
|
|
"github.com/containers/podman/v4/libpod/define"
|
|
"github.com/containers/podman/v4/pkg/rootless"
|
|
"github.com/containers/podman/v4/pkg/util"
|
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/opencontainers/runtime-tools/generate"
|
|
"github.com/sirupsen/logrus"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// DevicesFromPath computes a list of devices
|
|
func DevicesFromPath(g *generate.Generator, devicePath string) error {
|
|
if isCDIDevice(devicePath) {
|
|
registry := cdi.GetRegistry(
|
|
cdi.WithAutoRefresh(false),
|
|
)
|
|
if err := registry.Refresh(); err != nil {
|
|
logrus.Debugf("The following error was triggered when refreshing the CDI registry: %v", err)
|
|
}
|
|
_, err := registry.InjectDevices(g.Config, devicePath)
|
|
if 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) {
|
|
defaultMaskPaths := []string{"/proc/acpi",
|
|
"/proc/kcore",
|
|
"/proc/keys",
|
|
"/proc/latency_stats",
|
|
"/proc/timer_list",
|
|
"/proc/timer_stats",
|
|
"/proc/sched_debug",
|
|
"/proc/scsi",
|
|
"/sys/firmware",
|
|
"/sys/fs/selinux",
|
|
"/sys/dev/block",
|
|
}
|
|
|
|
if !privileged {
|
|
for _, mp := range defaultMaskPaths {
|
|
// 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 []string{
|
|
"/proc/asound",
|
|
"/proc/bus",
|
|
"/proc/fs",
|
|
"/proc/irq",
|
|
"/proc/sys",
|
|
"/proc/sysrq-trigger",
|
|
} {
|
|
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 := os.Stat(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.Errorf(err.Error())
|
|
}
|
|
if match {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|