Merge pull request #10307 from henry118/uidmap
Support multiple uid/gid mappings [1/2]
This commit is contained in:
98
internal/userns/idmap.go
Normal file
98
internal/userns/idmap.go
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file is copied and customized based on
|
||||
https://github.com/moby/moby/blob/master/pkg/idtools/idtools.go
|
||||
*/
|
||||
|
||||
package userns
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
const invalidID = 1<<32 - 1
|
||||
|
||||
var invalidUser = User{Uid: invalidID, Gid: invalidID}
|
||||
|
||||
// User is a Uid and Gid pair of a user
|
||||
//
|
||||
//nolint:revive
|
||||
type User struct {
|
||||
Uid uint32
|
||||
Gid uint32
|
||||
}
|
||||
|
||||
// IDMap contains the mappings of Uids and Gids.
|
||||
//
|
||||
//nolint:revive
|
||||
type IDMap struct {
|
||||
UidMap []specs.LinuxIDMapping `json:"UidMap"`
|
||||
GidMap []specs.LinuxIDMapping `json:"GidMap"`
|
||||
}
|
||||
|
||||
// ToHost returns the host user ID pair for the container ID pair.
|
||||
func (i IDMap) ToHost(pair User) (User, error) {
|
||||
var (
|
||||
target User
|
||||
err error
|
||||
)
|
||||
target.Uid, err = toHost(pair.Uid, i.UidMap)
|
||||
if err != nil {
|
||||
return invalidUser, err
|
||||
}
|
||||
target.Gid, err = toHost(pair.Gid, i.GidMap)
|
||||
if err != nil {
|
||||
return invalidUser, err
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
||||
// toHost takes an id mapping and a remapped ID, and translates the
|
||||
// ID to the mapped host ID. If no map is provided, then the translation
|
||||
// assumes a 1-to-1 mapping and returns the passed in id #
|
||||
func toHost(contID uint32, idMap []specs.LinuxIDMapping) (uint32, error) {
|
||||
if idMap == nil {
|
||||
return contID, nil
|
||||
}
|
||||
for _, m := range idMap {
|
||||
high, err := safeSum(m.ContainerID, m.Size)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if contID >= m.ContainerID && contID < high {
|
||||
hostID, err := safeSum(m.HostID, contID-m.ContainerID)
|
||||
if err != nil || hostID == invalidID {
|
||||
break
|
||||
}
|
||||
return hostID, nil
|
||||
}
|
||||
}
|
||||
return invalidID, fmt.Errorf("container ID %d cannot be mapped to a host ID", contID)
|
||||
}
|
||||
|
||||
// safeSum returns the sum of x and y. or an error if the result overflows
|
||||
func safeSum(x, y uint32) (uint32, error) {
|
||||
z := x + y
|
||||
if z < x || z < y {
|
||||
return invalidID, errors.New("ID overflow")
|
||||
}
|
||||
return z, nil
|
||||
}
|
||||
252
internal/userns/idmap_test.go
Normal file
252
internal/userns/idmap_test.go
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package userns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestToHost(t *testing.T) {
|
||||
idmap := IDMap{
|
||||
UidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1,
|
||||
Size: 2,
|
||||
},
|
||||
{
|
||||
ContainerID: 2,
|
||||
HostID: 4,
|
||||
Size: 1000,
|
||||
},
|
||||
},
|
||||
GidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 2,
|
||||
Size: 4,
|
||||
},
|
||||
{
|
||||
ContainerID: 4,
|
||||
HostID: 8,
|
||||
Size: 1000,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range []struct {
|
||||
container User
|
||||
host User
|
||||
}{
|
||||
{
|
||||
container: User{
|
||||
Uid: 0,
|
||||
Gid: 0,
|
||||
},
|
||||
host: User{
|
||||
Uid: 1,
|
||||
Gid: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
container: User{
|
||||
Uid: 1,
|
||||
Gid: 1,
|
||||
},
|
||||
host: User{
|
||||
Uid: 2,
|
||||
Gid: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
container: User{
|
||||
Uid: 2,
|
||||
Gid: 4,
|
||||
},
|
||||
host: User{
|
||||
Uid: 4,
|
||||
Gid: 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
container: User{
|
||||
Uid: 100,
|
||||
Gid: 200,
|
||||
},
|
||||
host: User{
|
||||
Uid: 102,
|
||||
Gid: 204,
|
||||
},
|
||||
},
|
||||
{
|
||||
container: User{
|
||||
Uid: 1001,
|
||||
Gid: 1003,
|
||||
},
|
||||
host: User{
|
||||
Uid: 1003,
|
||||
Gid: 1007,
|
||||
},
|
||||
},
|
||||
{
|
||||
container: User{
|
||||
Uid: 1004,
|
||||
Gid: 1008,
|
||||
},
|
||||
host: invalidUser,
|
||||
},
|
||||
{
|
||||
container: User{
|
||||
Uid: 2000,
|
||||
Gid: 2000,
|
||||
},
|
||||
host: invalidUser,
|
||||
},
|
||||
} {
|
||||
r, err := idmap.ToHost(test.container)
|
||||
assert.Equal(t, test.host, r)
|
||||
if r == invalidUser {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToHostOverflow(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
idmap IDMap
|
||||
user User
|
||||
}{
|
||||
{
|
||||
idmap: IDMap{
|
||||
UidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 1<<32 - 1000,
|
||||
HostID: 1000,
|
||||
Size: 10000,
|
||||
},
|
||||
},
|
||||
GidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 10000,
|
||||
},
|
||||
},
|
||||
},
|
||||
user: User{
|
||||
Uid: 1<<32 - 100,
|
||||
Gid: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
idmap: IDMap{
|
||||
UidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 10000,
|
||||
},
|
||||
},
|
||||
GidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 1<<32 - 1000,
|
||||
HostID: 1000,
|
||||
Size: 10000,
|
||||
},
|
||||
},
|
||||
},
|
||||
user: User{
|
||||
Uid: 0,
|
||||
Gid: 1<<32 - 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
idmap: IDMap{
|
||||
UidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 1<<32 - 1,
|
||||
},
|
||||
},
|
||||
GidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 1<<32 - 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
user: User{
|
||||
Uid: 1<<32 - 2,
|
||||
Gid: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
idmap: IDMap{
|
||||
UidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 1<<32 - 1,
|
||||
},
|
||||
},
|
||||
GidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 1<<32 - 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
user: User{
|
||||
Uid: 0,
|
||||
Gid: 1<<32 - 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
idmap: IDMap{
|
||||
UidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1,
|
||||
Size: 1<<32 - 1,
|
||||
},
|
||||
},
|
||||
GidMap: []specs.LinuxIDMapping{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1,
|
||||
Size: 1<<32 - 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
user: User{
|
||||
Uid: 1<<32 - 2,
|
||||
Gid: 1<<32 - 2,
|
||||
},
|
||||
},
|
||||
} {
|
||||
r, err := test.idmap.ToHost(test.user)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, r, invalidUser)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user