Skip to content

Commit

Permalink
idtools: add new function to fallback to overflow id
Browse files Browse the repository at this point in the history
add a new function ToHostOverflow() that instead of raising an error
when the mapping is not possible in the target user namespace, fall
back to using the overflow ID.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Apr 28, 2022
1 parent e2dae5e commit ed447c3
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
64 changes: 64 additions & 0 deletions pkg/idtools/idtools.go
Expand Up @@ -3,15 +3,18 @@ package idtools
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"os/user"
"sort"
"strconv"
"strings"
"sync"
"syscall"

"github.com/containers/storage/pkg/system"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)

// IDMap contains a single entry for user namespace range remapping. An array
Expand Down Expand Up @@ -203,6 +206,67 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
return target, err
}

var (
overflowUIDOnce sync.Once
overflowGIDOnce sync.Once
overflowUID int
overflowGID int
)

// getOverflowUID returns the UID mapped to the overflow user
func getOverflowUID() int {
overflowUIDOnce.Do(func() {
// 65534 is the value on older kernels where /proc/sys/kernel/overflowuid is not present
overflowUID = 65534
if content, err := ioutil.ReadFile("/proc/sys/kernel/overflowuid"); err == nil {
if tmp, err := strconv.Atoi(string(content)); err == nil {
overflowUID = tmp
}
}
})
return overflowUID
}

// getOverflowUID returns the GID mapped to the overflow user
func getOverflowGID() int {
overflowGIDOnce.Do(func() {
// 65534 is the value on older kernels where /proc/sys/kernel/overflowgid is not present
overflowGID = 65534
if content, err := ioutil.ReadFile("/proc/sys/kernel/overflowgid"); err == nil {
if tmp, err := strconv.Atoi(string(content)); err == nil {
overflowGID = tmp
}
}
})
return overflowGID
}

// ToHost returns the host UID and GID for the container uid, gid.
// Remapping is only performed if the ids aren't already the remapped root ids
// If the mapping is not possible because the target ID is not mapped into
// the namespace, then the overflow ID is used.
func (i *IDMappings) ToHostOverflow(pair IDPair) (IDPair, error) {
var err error
target := i.RootPair()

if pair.UID != target.UID {
target.UID, err = RawToHost(pair.UID, i.uids)
if err != nil {
target.UID = getOverflowUID()
logrus.Debugf("Failed to map UID %v to the target mapping, using the overflow ID %v", pair.UID, target.UID)
}
}

if pair.GID != target.GID {
target.GID, err = RawToHost(pair.GID, i.gids)
if err != nil {
target.GID = getOverflowGID()
logrus.Debugf("Failed to map GID %v to the target mapping, using the overflow ID %v", pair.GID, target.GID)
}
}
return target, nil
}

// ToContainer returns the container UID and GID for the host uid and gid
func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
uid, err := RawToContainer(pair.UID, i.uids)
Expand Down
42 changes: 42 additions & 0 deletions pkg/idtools/idtools_test.go
Expand Up @@ -46,6 +46,48 @@ func TestToHost(t *testing.T) {
}
}

func TestToHostOverflow(t *testing.T) {
idMappings := []IDMap{
{
ContainerID: 0,
HostID: 1000,
Size: 1,
},
{
ContainerID: 1,
HostID: 100000,
Size: 65536,
},
}

mappings := IDMappings{
uids: idMappings,
gids: idMappings,
}

pair, err := mappings.ToHostOverflow(IDPair{UID: 65538, GID: 0})
if err != nil {
t.Fatal(err)
}
if pair.UID != getOverflowUID() {
t.Fatalf("Converted to the wrong UID")
}
if pair.GID != 1000 {
t.Fatalf("Converted to the wrong GID")
}

pair, err = mappings.ToHostOverflow(IDPair{UID: 10, GID: 65539})
if err != nil {
t.Fatal(err)
}
if pair.UID != 100009 {
t.Fatalf("Converted to the wrong UID")
}
if pair.GID != getOverflowGID() {
t.Fatalf("Converted to the wrong GID")
}
}

func TestGetRootUIDGID(t *testing.T) {
mappingsUIDs := []IDMap{
{
Expand Down

0 comments on commit ed447c3

Please sign in to comment.