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 }