mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
configs: make id mappings int64 to better handle 32-bit
(This is a cherry-pick of 482e56379a1c2f8b2573f07c06013510e59f9eb8.)
Using ints for all of our mapping structures means that a 32-bit binary
errors out when trying to parse /proc/self/*id_map:
failed to cache mappings for userns: failed to parse uid_map of userns /proc/1/ns/user:
parsing id map failed: invalid format in line " 0 0 4294967295": integer overflow on token 4294967295
This issue was unearthed by commit 1912d5988b ("*: actually support
joining a userns with a new container") but the underlying issue has
been present since the docker/libcontainer days.
In theory, switching to uint32 (to match the spec) instead of int64
would also work, but keeping everything signed seems much less
error-prone. It's also important to note that a mapping might be too
large for an int on 32-bit, so we detect this during the mapping.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
@@ -21,9 +21,9 @@ type Rlimit struct {
|
||||
|
||||
// IDMap represents UID/GID Mappings for User Namespaces.
|
||||
type IDMap struct {
|
||||
ContainerID int `json:"container_id"`
|
||||
HostID int `json:"host_id"`
|
||||
Size int `json:"size"`
|
||||
ContainerID int64 `json:"container_id"`
|
||||
HostID int64 `json:"host_id"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
// Seccomp represents syscall restrictions
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package configs
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoUIDMap = errors.New("User namespaces enabled, but no uid mappings found.")
|
||||
@@ -16,11 +20,18 @@ func (c Config) HostUID(containerId int) (int, error) {
|
||||
if c.UidMappings == nil {
|
||||
return -1, errNoUIDMap
|
||||
}
|
||||
id, found := c.hostIDFromMapping(containerId, c.UidMappings)
|
||||
id, found := c.hostIDFromMapping(int64(containerId), c.UidMappings)
|
||||
if !found {
|
||||
return -1, errNoUserMap
|
||||
}
|
||||
return id, nil
|
||||
// If we are a 32-bit binary running on a 64-bit system, it's possible
|
||||
// the mapped user is too large to store in an int, which means we
|
||||
// cannot do the mapping. We can't just return an int64, because
|
||||
// os.Setuid() takes an int.
|
||||
if id > math.MaxInt {
|
||||
return -1, fmt.Errorf("mapping for uid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt)
|
||||
}
|
||||
return int(id), nil
|
||||
}
|
||||
// Return unchanged id.
|
||||
return containerId, nil
|
||||
@@ -39,11 +50,18 @@ func (c Config) HostGID(containerId int) (int, error) {
|
||||
if c.GidMappings == nil {
|
||||
return -1, errNoGIDMap
|
||||
}
|
||||
id, found := c.hostIDFromMapping(containerId, c.GidMappings)
|
||||
id, found := c.hostIDFromMapping(int64(containerId), c.GidMappings)
|
||||
if !found {
|
||||
return -1, errNoGroupMap
|
||||
}
|
||||
return id, nil
|
||||
// If we are a 32-bit binary running on a 64-bit system, it's possible
|
||||
// the mapped user is too large to store in an int, which means we
|
||||
// cannot do the mapping. We can't just return an int64, because
|
||||
// os.Setgid() takes an int.
|
||||
if id > math.MaxInt {
|
||||
return -1, fmt.Errorf("mapping for gid %d (host id %d) is larger than native integer size (%d)", containerId, id, math.MaxInt)
|
||||
}
|
||||
return int(id), nil
|
||||
}
|
||||
// Return unchanged id.
|
||||
return containerId, nil
|
||||
@@ -57,7 +75,7 @@ func (c Config) HostRootGID() (int, error) {
|
||||
|
||||
// Utility function that gets a host ID for a container ID from user namespace map
|
||||
// if that ID is present in the map.
|
||||
func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) {
|
||||
func (c Config) hostIDFromMapping(containerID int64, uMap []IDMap) (int64, bool) {
|
||||
for _, m := range uMap {
|
||||
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
|
||||
hostID := m.HostID + (containerID - m.ContainerID)
|
||||
|
||||
@@ -2268,7 +2268,7 @@ func ignoreTerminateErrors(err error) error {
|
||||
|
||||
func requiresRootOrMappingTool(c *configs.Config) bool {
|
||||
gidMap := []configs.IDMap{
|
||||
{ContainerID: 0, HostID: os.Getegid(), Size: 1},
|
||||
{ContainerID: 0, HostID: int64(os.Getegid()), Size: 1},
|
||||
}
|
||||
return !reflect.DeepEqual(c.GidMappings, gidMap)
|
||||
}
|
||||
|
||||
@@ -927,9 +927,9 @@ next:
|
||||
func setupUserNamespace(spec *specs.Spec, config *configs.Config) error {
|
||||
create := func(m specs.LinuxIDMapping) configs.IDMap {
|
||||
return configs.IDMap{
|
||||
HostID: int(m.HostID),
|
||||
ContainerID: int(m.ContainerID),
|
||||
Size: int(m.Size),
|
||||
HostID: int64(m.HostID),
|
||||
ContainerID: int64(m.ContainerID),
|
||||
Size: int64(m.Size),
|
||||
}
|
||||
}
|
||||
if spec.Linux != nil {
|
||||
|
||||
Reference in New Issue
Block a user