mirror of
https://github.com/lxc/crio-lxc.git
synced 2026-02-05 09:45:04 +01:00
162 lines
4.4 KiB
Go
162 lines
4.4 KiB
Go
package lxcri
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/opencontainers/runtime-spec/specs-go"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// namespace is a mapping from the namespace name
|
|
// as used in /proc/{pid}/ns and the namespace clone flag,
|
|
// as defined in `man 2 clone`.
|
|
type namespace struct {
|
|
Name string
|
|
CloneFlag int
|
|
}
|
|
|
|
var (
|
|
cgroupNamespace = namespace{"cgroup", unix.CLONE_NEWCGROUP}
|
|
ipcNamespace = namespace{"ipc", unix.CLONE_NEWIPC}
|
|
mountNamespace = namespace{"mnt", unix.CLONE_NEWNS}
|
|
networkNamespace = namespace{"net", unix.CLONE_NEWNET}
|
|
pidNamespace = namespace{"pid", unix.CLONE_NEWPID}
|
|
timeNamespace = namespace{"time", unix.CLONE_NEWTIME}
|
|
userNamespace = namespace{"user", unix.CLONE_NEWUSER}
|
|
utsNamespace = namespace{"uts", unix.CLONE_NEWUTS}
|
|
|
|
namespaceMap = map[specs.LinuxNamespaceType]namespace{
|
|
specs.CgroupNamespace: cgroupNamespace,
|
|
specs.IPCNamespace: ipcNamespace,
|
|
specs.MountNamespace: mountNamespace,
|
|
specs.NetworkNamespace: networkNamespace,
|
|
specs.PIDNamespace: pidNamespace,
|
|
// specs.TimeNamespace: timeNamespace,
|
|
specs.UserNamespace: userNamespace,
|
|
specs.UTSNamespace: utsNamespace,
|
|
}
|
|
)
|
|
|
|
func configureNamespaces(c *Container) error {
|
|
seenNamespaceTypes := map[specs.LinuxNamespaceType]bool{}
|
|
cloneNamespaces := make([]string, 0, len(c.Spec.Linux.Namespaces))
|
|
|
|
for _, ns := range c.Spec.Linux.Namespaces {
|
|
if _, seen := seenNamespaceTypes[ns.Type]; seen {
|
|
return fmt.Errorf("duplicate namespace %s", ns.Type)
|
|
}
|
|
seenNamespaceTypes[ns.Type] = true
|
|
|
|
n, supported := namespaceMap[ns.Type]
|
|
if !supported {
|
|
return fmt.Errorf("unsupported namespace %s", ns.Type)
|
|
}
|
|
|
|
if ns.Path == "" {
|
|
cloneNamespaces = append(cloneNamespaces, n.Name)
|
|
continue
|
|
}
|
|
|
|
configKey := fmt.Sprintf("lxc.namespace.share.%s", n.Name)
|
|
if err := c.setConfigItem(configKey, ns.Path); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return c.setConfigItem("lxc.namespace.clone", strings.Join(cloneNamespaces, " "))
|
|
}
|
|
|
|
func isNamespaceEnabled(spec *specs.Spec, nsType specs.LinuxNamespaceType) bool {
|
|
for _, ns := range spec.Linux.Namespaces {
|
|
if ns.Type == nsType {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func getNamespace(spec *specs.Spec, nsType specs.LinuxNamespaceType) *specs.LinuxNamespace {
|
|
for _, n := range spec.Linux.Namespaces {
|
|
if n.Type == nsType {
|
|
return &n
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// isNamespaceSharedWithHost returns true if the given namespace is nil.
|
|
// If the given namespace is not nil then the namespace then true is
|
|
// returned if the namespace path refers to the host namespace and
|
|
// false otherwise.
|
|
// Should be used with isNamespaceSharedWithHost(getNamespace(...))
|
|
func isNamespaceSharedWithRuntime(ns *specs.LinuxNamespace) (bool, error) {
|
|
// no namespace with this name defined
|
|
if ns == nil {
|
|
return true, nil
|
|
}
|
|
// namespaces without a target path are cloned
|
|
if ns.Path == "" {
|
|
return false, nil
|
|
}
|
|
|
|
// from `man namespaces` The /proc/[pid]/ns/ directory [...]
|
|
// In Linux 3.7 and earlier, these files were visible as hard links.
|
|
// If two processes are in the same namespace, then the device IDs and inode numbers
|
|
// of their /proc/[pid]/ns/xxx symbolic links will be the same;
|
|
// anapplication can check this using the stat.st_dev and stat.st_ino
|
|
// fields returned by stat(2).
|
|
// e.g `strace /usr/bin/stat -L /proc/1/ns/pid`
|
|
|
|
var stat unix.Stat_t
|
|
err := unix.Stat(ns.Path, &stat)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
var stat1 unix.Stat_t
|
|
err = unix.Stat("/proc/self/ns/pid", &stat1)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
sameNS := (stat.Dev == stat1.Dev) && (stat.Ino == stat1.Ino)
|
|
return sameNS, nil
|
|
}
|
|
|
|
// lxc does not set the hostname on shared namespaces
|
|
func setHostname(nsPath string, hostname string) error {
|
|
// setns only affects the current thread
|
|
runtime.LockOSThread()
|
|
defer runtime.UnlockOSThread()
|
|
|
|
f, err := os.Open(nsPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open container uts namespace %q: %w", nsPath, err)
|
|
}
|
|
// #nosec
|
|
defer f.Close()
|
|
|
|
self, err := os.Open("/proc/self/ns/uts")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open uts namespace : %w", err)
|
|
}
|
|
// #nosec
|
|
defer func() {
|
|
unix.Setns(int(self.Fd()), unix.CLONE_NEWUTS)
|
|
self.Close()
|
|
}()
|
|
|
|
err = unix.Setns(int(f.Fd()), unix.CLONE_NEWUTS)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to switch to UTS namespace %s: %w", nsPath, err)
|
|
}
|
|
err = unix.Sethostname([]byte(hostname))
|
|
if err != nil {
|
|
return fmt.Errorf("unix.Sethostname failed: %w", err)
|
|
}
|
|
return nil
|
|
}
|