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  }