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

Commit

Permalink
agent: make NoPivotRoot config depend on / fs type
Browse files Browse the repository at this point in the history
Make NoPivotRoot depend on the actual FS type of `/` being rootfs,
instead of agent being the init process.
In this way, an initrd built without AGENT_INIT can still be used to run
containers.

Fixes: #611

Signed-off-by: Marco Vedovati <[email protected]>
  • Loading branch information
marcov committed Jul 22, 2019
1 parent a1c9d50 commit 5ffb2a6
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 8 deletions.
11 changes: 8 additions & 3 deletions agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -1327,13 +1327,18 @@ func realMain() error {
r := &agentReaper{}
r.init()

fsType, err := getMountFSType("/")
if err != nil {
return err
}

// Initialize unique sandbox structure.
s := &sandbox{
containers: make(map[string]*container),
running: false,
// pivot_root won't work for init, see
// Documention/filesystem/ramfs-rootfs-initramfs.txt
noPivotRoot: os.Getpid() == 1,
// pivot_root won't work for initramfs, see
// Documentation/filesystem/ramfs-rootfs-initramfs.txt
noPivotRoot: (fsType == typeRootfs),
subreaper: r,
pciDeviceMap: make(map[string]string),
deviceWatchers: make(map[string](chan string)),
Expand Down
48 changes: 43 additions & 5 deletions mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,32 @@
package main

import (
"bufio"
"context"
"fmt"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"syscall"

pb "github.com/kata-containers/agent/protocols/grpc"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
"google.golang.org/grpc/codes"
grpcStatus "google.golang.org/grpc/status"
)

const (
type9pFs = "9p"
typeVirtioFS = "virtio_fs"
typeTmpFs = "tmpfs"
devPrefix = "/dev/"
mountPerm = os.FileMode(0755)
type9pFs = "9p"
typeVirtioFS = "virtio_fs"
typeRootfs = "rootfs"
typeTmpFs = "tmpfs"
devPrefix = "/dev/"
procMountStats = "/proc/self/mountstats"
mountPerm = os.FileMode(0755)
)

var flagList = map[string]int{
Expand Down Expand Up @@ -385,3 +390,36 @@ func addStorages(ctx context.Context, storages []*pb.Storage, s *sandbox) (mount

return mountList, nil
}

// getMountFSType returns the FS type corresponding to the passed mount point and
// any error ecountered.
func getMountFSType(mountPoint string) (string, error) {
if mountPoint == "" {
return "", errors.Errorf("Invalid mount point '%s'", mountPoint)
}

mountstats, err := os.Open(procMountStats)
if err != nil {
return "", errors.Wrapf(err, "Failed to open file '%s'", procMountStats)
}
defer mountstats.Close()

// Refer to fs/proc_namespace.c:show_vfsstat() for
// the file format.
re := regexp.MustCompile(fmt.Sprintf(`device .+ mounted on %s with fstype (.+)`, mountPoint))

scanner := bufio.NewScanner(mountstats)
for scanner.Scan() {
line := scanner.Text()
matches := re.FindStringSubmatch(line)
if len(matches) > 1 {
return matches[1], nil
}
}

if err := scanner.Err(); err != nil {
return "", errors.Wrapf(err, "Failed to parse proc mount stats file %s", procMountStats)
}

return "", errors.Errorf("Failed to find FS type for mount point '%s'", mountPoint)
}
43 changes: 43 additions & 0 deletions mount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,46 @@ func TestMountEnsureDestinationExists(t *testing.T) {
}
}
}

func TestGetMountFSType(t *testing.T) {
assert := assert.New(t)

// Type used to hold function parameters and expected results.
type testData struct {
param1 string
expectedResult string
expectError bool
}

// List of tests to run including the expected results
data := []testData{
// failure scenarios
{"/thisPathShouldNotBeAMountPoint", "", true},

// success scenarios
{"/proc", "proc", false},
{"/sys", "sysfs", false},
{"/run", "tmpfs", false},
}

// Run the tests
for i, d := range data {
// Create a test-specific string that is added to each assert
// call. It will be displayed if any assert test fails.
msg := fmt.Sprintf("test[%d]: %+v", i, d)

// Call the function under test
result, err := getMountFSType(d.param1)

if d.expectError {
assert.Error(err, msg)

// If an error is expected, there is no point
// performing additional checks.
continue
}

assert.NoError(err, msg)
assert.Equal(d.expectedResult, result, msg)
}
}

0 comments on commit 5ffb2a6

Please sign in to comment.