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 12, 2019
1 parent 5e67e04 commit 7e16d10
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
10 changes: 10 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 Expand Up @@ -337,6 +341,12 @@ func beforeSubcommands(c *cli.Context) error {

kataLog.WithFields(fields).Info()

// Check if running rootlessly, and setup for rootless execution
err = rootless.SetRootless()
if err != nil {
fatal(err)
}

// make the data accessible to the sub-commands.
c.App.Metadata["runtimeConfig"] = runtimeConfig
c.App.Metadata["configFile"] = configFile
Expand Down
79 changes: 79 additions & 0 deletions pkg/rootless/rootless.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package rootless

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

"github.com/sirupsen/logrus"
)

var (
isRootless bool
rootlessDir = os.Getenv("XDG_RUNTIME_DIR")
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 {
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.Warnf("Running as rootless")
isRootless = true
return nil
}
}
}

// IsRootless states whether kata is being ran with root or not
func IsRootless() bool {
return isRootless
}

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

package rootless

import (
"fmt"
"os"
"testing"

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

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) {
// by default isRootless should be set to false initially
assert.False(t, IsRootless())

uidMapPathStore := uidMapPath
uidMapPath = "/tmp/testUIDMapFile"
defer func() {
uidMapPath = uidMapPathStore
os.RemoveAll(uidMapPath)
isRootless = false
}()

mapping := "\t0\t1000\t5555"
err := createTestUidMapFile(mapping)
if err != nil {
fmt.Printf("Could not create test file: %v", err)
os.Exit(1)
}

err = SetRootless()
assert.NoError(t, err)

assert.True(t, IsRootless())
}

// TestSetRootlessRootUID0 tests that isRootless is not set when
// the host UID is 0
func TestSetRootlessRootUID0(t *testing.T) {
// by default isRootless should be set to false initially
assert.False(t, IsRootless())

uidMapPathStore := uidMapPath
uidMapPath = "/tmp/testUIDMapFile"
defer func() {
uidMapPath = uidMapPathStore
os.RemoveAll(uidMapPath)
isRootless = false
}()

mapping := "\t0\t0\t5555"
err := createTestUidMapFile(mapping)
if err != nil {
fmt.Printf("Could not create test file: %v", err)
os.Exit(1)
}

err = SetRootless()
assert.NoError(t, err)

assert.False(t, IsRootless())
}

0 comments on commit 7e16d10

Please sign in to comment.