Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

rootless: add rootless to kata #1875

Merged
merged 6 commits into from
Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@

[[constraint]]
name = "github.com/vishvananda/netlink"
revision = "c2a3de3b38bd00f07290c3c5e12b4dbc04ec8666"
revision = "c8c507c80ea28385caac72b682dd066e44943913"
gabibeyer marked this conversation as resolved.
Show resolved Hide resolved

[[constraint]]
name = "github.com/vishvananda/netns"
revision = "86bef332bfc3b59b7624a600bd53009ce91a9829"

[[constraint]]
name = "golang.org/x/sys"
revision = "1d2aa6dbdea45adaaebb9905d0666e4537563829"
revision = "88d2dcc510266da9f7f8c7f34e1940716cab5f5c"

[[constraint]]
name = "github.com/sirupsen/logrus"
Expand Down
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
18 changes: 18 additions & 0 deletions pkg/katautils/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/kata-containers/runtime/pkg/rootless"
)

const ctrsMappingDirMode = os.FileMode(0750)
Expand All @@ -22,6 +25,11 @@ func SetCtrsMapTreePath(path string) {
ctrsMapTreePath = path
}

// doUpdatePath returns whether a ctrsMapTreePath needs to be updated with a rootless prefix
func doUpdatePath() bool {
return rootless.IsRootless() && !strings.HasPrefix(ctrsMapTreePath, rootless.GetRootlessDir())
}

// FetchContainerIDMapping This function assumes it should find only one file inside the container
// ID directory. If there are several files, we could not determine which
// file name corresponds to the sandbox ID associated, and this would throw
Expand All @@ -31,6 +39,10 @@ func FetchContainerIDMapping(containerID string) (string, error) {
return "", fmt.Errorf("Missing container ID")
}

if doUpdatePath() {
SetCtrsMapTreePath(filepath.Join(rootless.GetRootlessDir(), ctrsMapTreePath))
}

dirPath := filepath.Join(ctrsMapTreePath, containerID)

files, err := ioutil.ReadDir(dirPath)
Expand Down Expand Up @@ -62,6 +74,9 @@ func AddContainerIDMapping(ctx context.Context, containerID, sandboxID string) e
return fmt.Errorf("Missing sandbox ID")
}

if doUpdatePath() {
SetCtrsMapTreePath(filepath.Join(rootless.GetRootlessDir(), ctrsMapTreePath))
}
parentPath := filepath.Join(ctrsMapTreePath, containerID)

if err := os.RemoveAll(parentPath); err != nil {
Expand All @@ -86,6 +101,9 @@ func DelContainerIDMapping(ctx context.Context, containerID string) error {
return fmt.Errorf("Missing container ID")
}

if doUpdatePath() {
SetCtrsMapTreePath(filepath.Join(rootless.GetRootlessDir(), ctrsMapTreePath))
}
path := filepath.Join(ctrsMapTreePath, containerID)

return os.RemoveAll(path)
Expand Down
123 changes: 123 additions & 0 deletions pkg/rootless/rootless.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

package rootless

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

"github.com/pkg/errors"
"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

// lock for the initRootless and isRootless variables
rLock sync.Mutex

// XDG_RUNTIME_DIR defines the base directory relative to
// which user-specific non-essential runtime files are stored.
rootlessDir = os.Getenv("XDG_RUNTIME_DIR")
gabibeyer marked this conversation as resolved.
Show resolved Hide resolved

// 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 {
marcov marked this conversation as resolved.
Show resolved Hide resolved
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
}

var parseError = errors.Errorf("Failed to parse uid map file %s", uidMapPath)
// 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))
// do some sanity checks
if len(ids) != 3 {
return parseError
}
userNSUid, err := strconv.ParseUint(ids[0], 10, 0)
if err != nil {
return parseError
}
hostUID, err := strconv.ParseUint(ids[1], 10, 0)
if err != nil {
return parseError
}
rangeUID, err := strconv.ParseUint(ids[1], 10, 0)
if err != nil || rangeUID == 0 {
return parseError
}

if userNSUid == 0 && hostUID != 0 {
rootlessLog.Info("Running as rootless")
isRootless = true
return nil
}
}
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, IsRootless depends on SetRootless being called prior which is not ideal.
I would rather just have a single function called IsRootless in this package. It could check if it is called before and return the result.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed? @amshinde ACK?

}

// GetRootlessDir returns the path to the location for rootless
// container and sandbox storage
func GetRootlessDir() string {
return rootlessDir
}
Loading