mirror of
				https://github.com/containers/podman.git
				synced 2025-11-04 17:07:20 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			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.Errorf(err.Error())
 | 
						|
			}
 | 
						|
			if match {
 | 
						|
				return false
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true
 | 
						|
}
 |