Skip to content

Commit

Permalink
rootless: add rootless logic
Browse files Browse the repository at this point in the history
Add the ability to check whether kata is running rootlessly or
not. Add the setup of the rootless directory located in the dir
/run/user/<UID> directory.

Fixes: kata-containers#1874

Signed-off-by: Gabi Beyer <[email protected]>
  • Loading branch information
Gabi Beyer committed Jul 30, 2019
1 parent 3255640 commit 94b2b1c
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
4 changes: 4 additions & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"syscall"

"github.com/kata-containers/runtime/pkg/katautils"
"github.com/kata-containers/runtime/pkg/rootless"
"github.com/kata-containers/runtime/pkg/signals"
vc "github.com/kata-containers/runtime/virtcontainers"
vf "github.com/kata-containers/runtime/virtcontainers/factory"
Expand Down Expand Up @@ -241,6 +242,9 @@ func setExternalLoggers(ctx context.Context, logger *logrus.Entry) {

// Set the katautils package logger
katautils.SetLogger(ctx, logger, originalLoggerLevel)

// Set the rootless package logger
rootless.SetLogger(ctx, logger)
}

// beforeSubcommands is the function to perform preliminary checks
Expand Down
97 changes: 97 additions & 0 deletions pkg/rootless/rootless.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package rootless

import (
"bufio"
"context"
"io"
"os"
"strings"

"github.com/sirupsen/logrus"
)

var (
// initRootless states whether the isRootless variable
// has been set yet
initRootless bool

// isRootless states whether execution is rootless or not
isRootless bool

// XDG_RUNTIME_DIR defines the base directory relative to
// which user-specific non-essential runtime files are stored.
rootlessDir = os.Getenv("XDG_RUNTIME_DIR")

// uidMapPath defines the location of the uid_map file to
// determine whether a user is root or not
uidMapPath = "/proc/self/uid_map"

rootlessLog = logrus.WithFields(logrus.Fields{
"source": "rootless",
})
)

// SetLogger sets up a logger for the rootless pkg
func SetLogger(ctx context.Context, logger *logrus.Entry) {
fields := rootlessLog.Data
rootlessLog = logger.WithFields(fields)
}

// setRootless reads a uid_map file, compares the UID of the
// user inside the container vs on the host. If the host UID
// is not root, but the container ID is, it can be determined
// the user is running rootlessly.
func setRootless() error {
initRootless = true
file, err := os.Open(uidMapPath)
if err != nil {
return err
}
defer file.Close()

buf := bufio.NewReader(file)
for {
line, _, err := buf.ReadLine()
if err != nil {
if err == io.EOF {
return nil
}
return err
}
if line == nil {
return nil
}

// if the container id (id[0]) is 0 (root inside the container)
// has a mapping to the host id (id[1]) that is not root, then
// it can be determined that the host user is running rootless
ids := strings.Fields(string(line))
if ids[0] == "0" && ids[1] != "0" {
rootlessLog.Infof("Running as rootless")
isRootless = true
return nil
}
}
}

// IsRootless states whether kata is being ran with root or not
func IsRootless() bool {
if !initRootless {
err := setRootless()
if err != nil {
rootlessLog.Errorf("Unable to determine if running rootless")
}
}
return isRootless
}

// GetRootlessDir returns the path to the location for rootless
// container and sandbox storage
func GetRootlessDir() string {
return rootlessDir
}
88 changes: 88 additions & 0 deletions pkg/rootless/rootless_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package rootless

import (
"io/ioutil"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

var uidMapPathStore = uidMapPath

func createTestUIDMapFile(input string) error {
f, err := os.Create(uidMapPath)
if err != nil {
return err
}
defer f.Close()

_, err = f.WriteString(input)
if err != nil {
return err
}

return nil
}

// TestSetRootlessRootlessUID1000 tests that isRootless is set to
// true when a host UID is not 0
func TestSetRootlessRootlessUID1000(t *testing.T) {
assert := assert.New(t)

// by default isRootless should be set to false initially
assert.False(IsRootless())

tmpDir, err := ioutil.TempDir("", "")
assert.NoError(err)

uidMapPath = filepath.Join(tmpDir, "testUIDMapFile")
defer func() {
uidMapPath = uidMapPathStore
os.RemoveAll(tmpDir)
isRootless = false
}()

mapping := "\t0\t1000\t5555"
err = createTestUIDMapFile(mapping)
assert.NoError(err)

err = SetRootless()
assert.NoError(err)

assert.True(IsRootless())
}

// TestSetRootlessRootUID0 tests that isRootless is not set when
// the host UID is 0
func TestSetRootlessRootUID0(t *testing.T) {
assert := assert.New(t)

// by default isRootless should be set to false initially
assert.False(IsRootless())

tmpDir, err := ioutil.TempDir("", "")
assert.NoError(err)

uidMapPath = filepath.Join(tmpDir, "testUIDMapFile")
defer func() {
uidMapPath = uidMapPathStore
os.RemoveAll(uidMapPath)
isRootless = false
}()

mapping := "\t0\t0\t5555"
err = createTestUIDMapFile(mapping)
assert.NoError(err)

err = SetRootless()
assert.NoError(err)

assert.False(IsRootless())
}

0 comments on commit 94b2b1c

Please sign in to comment.