github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/configs/namespaces_linux.go (about)

     1  package configs
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"sync"
     7  )
     8  
     9  const (
    10  	NEWNET    NamespaceType = "NEWNET"
    11  	NEWPID    NamespaceType = "NEWPID"
    12  	NEWNS     NamespaceType = "NEWNS"
    13  	NEWUTS    NamespaceType = "NEWUTS"
    14  	NEWIPC    NamespaceType = "NEWIPC"
    15  	NEWUSER   NamespaceType = "NEWUSER"
    16  	NEWCGROUP NamespaceType = "NEWCGROUP"
    17  	NEWTIME   NamespaceType = "NEWTIME"
    18  )
    19  
    20  var (
    21  	nsLock              sync.Mutex
    22  	supportedNamespaces = make(map[NamespaceType]bool)
    23  )
    24  
    25  // NsName converts the namespace type to its filename
    26  func NsName(ns NamespaceType) string {
    27  	switch ns {
    28  	case NEWNET:
    29  		return "net"
    30  	case NEWNS:
    31  		return "mnt"
    32  	case NEWPID:
    33  		return "pid"
    34  	case NEWIPC:
    35  		return "ipc"
    36  	case NEWUSER:
    37  		return "user"
    38  	case NEWUTS:
    39  		return "uts"
    40  	case NEWCGROUP:
    41  		return "cgroup"
    42  	case NEWTIME:
    43  		return "time"
    44  	}
    45  	return ""
    46  }
    47  
    48  // IsNamespaceSupported returns whether a namespace is available or
    49  // not
    50  func IsNamespaceSupported(ns NamespaceType) bool {
    51  	nsLock.Lock()
    52  	defer nsLock.Unlock()
    53  	supported, ok := supportedNamespaces[ns]
    54  	if ok {
    55  		return supported
    56  	}
    57  	nsFile := NsName(ns)
    58  	// if the namespace type is unknown, just return false
    59  	if nsFile == "" {
    60  		return false
    61  	}
    62  	// We don't need to use /proc/thread-self here because the list of
    63  	// namespace types is unrelated to the thread. This lets us avoid having to
    64  	// do runtime.LockOSThread.
    65  	_, err := os.Stat("/proc/self/ns/" + nsFile)
    66  	// a namespace is supported if it exists and we have permissions to read it
    67  	supported = err == nil
    68  	supportedNamespaces[ns] = supported
    69  	return supported
    70  }
    71  
    72  func NamespaceTypes() []NamespaceType {
    73  	return []NamespaceType{
    74  		NEWUSER, // Keep user NS always first, don't move it.
    75  		NEWIPC,
    76  		NEWUTS,
    77  		NEWNET,
    78  		NEWPID,
    79  		NEWNS,
    80  		NEWCGROUP,
    81  		NEWTIME,
    82  	}
    83  }
    84  
    85  // Namespace defines configuration for each namespace.  It specifies an
    86  // alternate path that is able to be joined via setns.
    87  type Namespace struct {
    88  	Type NamespaceType `json:"type"`
    89  	Path string        `json:"path"`
    90  }
    91  
    92  func (n *Namespace) GetPath(pid int) string {
    93  	return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type))
    94  }
    95  
    96  func (n *Namespaces) Remove(t NamespaceType) bool {
    97  	i := n.index(t)
    98  	if i == -1 {
    99  		return false
   100  	}
   101  	*n = append((*n)[:i], (*n)[i+1:]...)
   102  	return true
   103  }
   104  
   105  func (n *Namespaces) Add(t NamespaceType, path string) {
   106  	i := n.index(t)
   107  	if i == -1 {
   108  		*n = append(*n, Namespace{Type: t, Path: path})
   109  		return
   110  	}
   111  	(*n)[i].Path = path
   112  }
   113  
   114  func (n *Namespaces) index(t NamespaceType) int {
   115  	for i, ns := range *n {
   116  		if ns.Type == t {
   117  			return i
   118  		}
   119  	}
   120  	return -1
   121  }
   122  
   123  func (n *Namespaces) Contains(t NamespaceType) bool {
   124  	return n.index(t) != -1
   125  }
   126  
   127  func (n *Namespaces) PathOf(t NamespaceType) string {
   128  	i := n.index(t)
   129  	if i == -1 {
   130  		return ""
   131  	}
   132  	return (*n)[i].Path
   133  }