github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/configs/config_linux.go (about) 1 package configs 2 3 import ( 4 "errors" 5 "fmt" 6 "math" 7 ) 8 9 var ( 10 errNoUIDMap = errors.New("user namespaces enabled, but no uid mappings found") 11 errNoGIDMap = errors.New("user namespaces enabled, but no gid mappings found") 12 ) 13 14 // Please check https://man7.org/linux/man-pages/man2/personality.2.html for const details. 15 // https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/personality.h 16 const ( 17 PerLinux = 0x0000 18 PerLinux32 = 0x0008 19 ) 20 21 type LinuxPersonality struct { 22 // Domain for the personality 23 // can only contain values "LINUX" and "LINUX32" 24 Domain int `json:"domain"` 25 } 26 27 // HostUID gets the translated uid for the process on host which could be 28 // different when user namespaces are enabled. 29 func (c Config) HostUID(containerId int) (int, error) { 30 if c.Namespaces.Contains(NEWUSER) { 31 if len(c.UIDMappings) == 0 { 32 return -1, errNoUIDMap 33 } 34 id, found := c.hostIDFromMapping(int64(containerId), c.UIDMappings) 35 if !found { 36 return -1, fmt.Errorf("user namespaces enabled, but no mapping found for uid %d", containerId) 37 } 38 // If we are a 32-bit binary running on a 64-bit system, it's possible 39 // the mapped user is too large to store in an int, which means we 40 // cannot do the mapping. We can't just return an int64, because 41 // os.Setuid() takes an int. 42 if id > math.MaxInt { 43 return -1, fmt.Errorf("mapping for uid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt) 44 } 45 return int(id), nil 46 } 47 // Return unchanged id. 48 return containerId, nil 49 } 50 51 // HostRootUID gets the root uid for the process on host which could be non-zero 52 // when user namespaces are enabled. 53 func (c Config) HostRootUID() (int, error) { 54 return c.HostUID(0) 55 } 56 57 // HostGID gets the translated gid for the process on host which could be 58 // different when user namespaces are enabled. 59 func (c Config) HostGID(containerId int) (int, error) { 60 if c.Namespaces.Contains(NEWUSER) { 61 if len(c.GIDMappings) == 0 { 62 return -1, errNoGIDMap 63 } 64 id, found := c.hostIDFromMapping(int64(containerId), c.GIDMappings) 65 if !found { 66 return -1, fmt.Errorf("user namespaces enabled, but no mapping found for gid %d", containerId) 67 } 68 // If we are a 32-bit binary running on a 64-bit system, it's possible 69 // the mapped user is too large to store in an int, which means we 70 // cannot do the mapping. We can't just return an int64, because 71 // os.Setgid() takes an int. 72 if id > math.MaxInt { 73 return -1, fmt.Errorf("mapping for gid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt) 74 } 75 return int(id), nil 76 } 77 // Return unchanged id. 78 return containerId, nil 79 } 80 81 // HostRootGID gets the root gid for the process on host which could be non-zero 82 // when user namespaces are enabled. 83 func (c Config) HostRootGID() (int, error) { 84 return c.HostGID(0) 85 } 86 87 // Utility function that gets a host ID for a container ID from user namespace map 88 // if that ID is present in the map. 89 func (c Config) hostIDFromMapping(containerID int64, uMap []IDMap) (int64, bool) { 90 for _, m := range uMap { 91 if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) { 92 hostID := m.HostID + (containerID - m.ContainerID) 93 return hostID, true 94 } 95 } 96 return -1, false 97 }