From c4628d79d26c47bfbac9a3b22d684ee5fd78973c Mon Sep 17 00:00:00 2001 From: Jonas Dohse Date: Thu, 30 May 2019 16:11:22 +0200 Subject: [PATCH] Stop sorting uid and gid ranges in id maps Moby currently sorts uid and gid ranges in id maps. This causes subuid and subgid files to be interpreted wrongly. The subuid file ``` > cat /etc/subuid jonas:100000:1000 jonas:1000:1 ``` configures that the container uids 0-999 are mapped to the host uids 100000-100999 and uid 1000 in the container is mapped to uid 1000 on the host. The expected uid_map is: ``` > docker run ubuntu cat /proc/self/uid_map 0 100000 1000 1000 1000 1 ``` Moby currently sorts the ranges by the first id in the range. Therefore with the subuid file above the uid 0 in the container is mapped to uid 100000 on host and the uids 1-1000 in container are mapped to the uids 1-1000 on the host. The resulting uid_map is: ``` > docker run ubuntu cat /proc/self/uid_map 0 1000 1 1 100000 1000 ``` The ordering was implemented to work around a limitation in Linux 3.8. This is fixed since Linux 3.9 as stated on the user namespaces manpage [1]: > In the initial implementation (Linux 3.8), this requirement was > satisfied by a simplistic implementation that imposed the further > requirement that the values in both field 1 and field 2 of successive > lines must be in ascending numerical order, which prevented some > otherwise valid maps from being created. Linux 3.9 and later fix this > limitation, allowing any valid set of nonoverlapping maps. This fix changes the interpretation of subuid and subgid files which do not have the ids of in the numerical order for each individual user. This breaks users that rely on the current behaviour. The desired mapping above - map low user ids in the container to high user ids on the host and some higher user ids in the container to lower user on host - can unfortunately not archived with the current behaviour. [1] http://man7.org/linux/man-pages/man7/user_namespaces.7.html Signed-off-by: Jonas Dohse --- pkg/idtools/idtools.go | 3 --- pkg/idtools/idtools_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 pkg/idtools/idtools_test.go diff --git a/pkg/idtools/idtools.go b/pkg/idtools/idtools.go index 230422eac8..b3af7a4226 100644 --- a/pkg/idtools/idtools.go +++ b/pkg/idtools/idtools.go @@ -4,7 +4,6 @@ import ( "bufio" "fmt" "os" - "sort" "strconv" "strings" ) @@ -203,8 +202,6 @@ func (i *IdentityMapping) GIDs() []IDMap { func createIDMap(subidRanges ranges) []IDMap { idMap := []IDMap{} - // sort the ranges by lowest ID first - sort.Sort(subidRanges) containerID := 0 for _, idrange := range subidRanges { idMap = append(idMap, IDMap{ diff --git a/pkg/idtools/idtools_test.go b/pkg/idtools/idtools_test.go new file mode 100644 index 0000000000..7627d1998c --- /dev/null +++ b/pkg/idtools/idtools_test.go @@ -0,0 +1,28 @@ +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "testing" + + "gotest.tools/assert" +) + +func TestCreateIDMapOrder(t *testing.T) { + subidRanges := ranges{ + {100000, 1000}, + {1000, 1}, + } + + idMap := createIDMap(subidRanges) + assert.DeepEqual(t, idMap, []IDMap{ + { + ContainerID: 0, + HostID: 100000, + Size: 1000, + }, + { + ContainerID: 1000, + HostID: 1000, + Size: 1, + }, + }) +}