Skip to content
Open
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
5 changes: 5 additions & 0 deletions pkg/sentry/fsimpl/proc/filesystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ type InternalData struct {
// should exist in the procfs.
GVisorMarkerFile bool

// OverrideProcs is a list of proc files to override with stubs. The
// /proc/ prefix is removed (e.g., this contains filenames like
// "kallsyms").
OverrideProcs []string

// Cgroups-internal data.
Cgroups map[string]string
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/sentry/fsimpl/proc/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func (fs *filesystem) newTasksInode(ctx context.Context, k *kernel.Kernel, pidns
}
fs.addNvproxyFiles(ctx, root, k, contents)

for _, name := range internalData.OverrideProcs {
contents[name] = fs.newInode(ctx, root, 0444, newStaticFile(""))
}

fs.newTasksInodeExtra(ctx, root, internalData, k, contents)

inode := &tasksInode{
Expand Down
63 changes: 57 additions & 6 deletions pkg/sentry/fsimpl/proc/tasks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package proc

import (
"fmt"
"io"
"math"
"path"
"strconv"
Expand Down Expand Up @@ -105,6 +106,15 @@ var (
)

func setup(t *testing.T) *testutil.System {
return setupWithData(t, &InternalData{
Cgroups: map[string]string{
"cpuset": "/foo/cpuset",
"memory": "/foo/memory",
},
})
}

func setupWithData(t *testing.T, data *InternalData) *testutil.System {
k, err := testutil.Boot()
if err != nil {
t.Fatalf("Error creating kernel: %v", err)
Expand Down Expand Up @@ -139,12 +149,7 @@ func setup(t *testing.T) *testutil.System {
}
mntOpts := &vfs.MountOptions{
GetFilesystemOptions: vfs.GetFilesystemOptions{
InternalData: &InternalData{
Cgroups: map[string]string{
"cpuset": "/foo/cpuset",
"memory": "/foo/memory",
},
},
InternalData: data,
},
}
if _, err := k.VFS().MountAt(ctx, creds, "", pop, Name, mntOpts); err != nil {
Expand All @@ -162,6 +167,52 @@ func TestTasksEmpty(t *testing.T) {
s.AssertDirentOffsets(collector, tasksStaticFilesNextOffs)
}

func TestTasksWithOverrideProc(t *testing.T) {
s := setupWithData(t, &InternalData{
Cgroups: map[string]string{
"cpuset": "/foo/cpuset",
"memory": "/foo/memory",
},
OverrideProcs: []string{"kallsyms", "arbitrary_file"},
})
defer s.Destroy()

expected := make(map[string]testutil.DirentType)
for k, v := range tasksStaticFiles {
expected[k] = v
}
expected["kallsyms"] = linux.DT_REG
expected["arbitrary_file"] = linux.DT_REG

collector := s.ListDirents(s.PathOpAtRoot("/proc"))
s.AssertAllDirentTypes(collector, expected)

// Verify file contents are empty.
for _, name := range []string{"kallsyms", "arbitrary_file"} {
filePath := path.Join("/proc", name)
fd, err := s.VFS.OpenAt(
s.Ctx,
s.Creds,
s.PathOpAtRoot(filePath),
&vfs.OpenOptions{},
)
if err != nil {
t.Fatalf("vfs.OpenAt(%q) failed: %v", filePath, err)
}
defer fd.DecRef(s.Ctx)

buf := make([]byte, 1024)
bufIOSeq := usermem.BytesIOSequence(buf)
n, err := fd.Read(s.Ctx, bufIOSeq, vfs.ReadOptions{})
if err != nil && err != io.EOF {
t.Errorf("read %q failed: %v", filePath, err)
}
if n != 0 {
t.Errorf("expected empty file %q, got %d bytes: %q", filePath, n, buf[:n])
}
}
}

func TestTasks(t *testing.T) {
s := setup(t)
defer s.Destroy()
Expand Down
13 changes: 13 additions & 0 deletions runsc/boot/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"io"
"os"
"strconv"
"strings"
time2 "time"

specs "github.com/opencontainers/runtime-spec/specs-go"
Expand Down Expand Up @@ -524,3 +525,15 @@ func (l *Loader) saveWithOpts(saveOpts *state.SaveOpts, execOpts *control.SaveRe
}
return state.SaveWithOpts(saveOpts, execOpts)
}

func procFiles(conf *config.Config) []string {
var files []string

if conf.OverrideProcs != "" {
for _, val := range strings.Split(conf.OverrideProcs, ",") {
files = append(files, strings.TrimPrefix(val, "/proc/"))
}
}

return files
}
1 change: 1 addition & 0 deletions runsc/boot/restore_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
func newProcInternalData(conf *config.Config, _ *specs.Spec) *proc.InternalData {
return &proc.InternalData{
GVisorMarkerFile: conf.GVisorMarkerFile,
OverrideProcs: procFiles(conf),
}
}

Expand Down
3 changes: 3 additions & 0 deletions runsc/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ type Config struct {
// GVisorMarkerFile enables the /proc/gvisor/kernel_is_gvisor marker file.
GVisorMarkerFile bool `flag:"gvisor-marker-file"`

// OverrideProcs is a comma-separated list of proc files to override with stubs.
OverrideProcs string `flag:"override-procs"`

// SystrapDisableSyscallPatching disables syscall patching in Systrap.
SystrapDisableSyscallPatching bool `flag:"systrap-disable-syscall-patching"`

Expand Down
1 change: 1 addition & 0 deletions runsc/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ func RegisterFlags(flagSet *flag.FlagSet) {
flagSet.Var(hostUDSPtr(HostUDSNone), flagHostUDS, "controls permission to access host Unix-domain sockets. Values: none|open|create|all, default: none")
flagSet.Var(hostFifoPtr(HostFifoNone), "host-fifo", "controls permission to access host FIFOs (or named pipes). Values: none|open, default: none")
flagSet.Bool("gvisor-marker-file", false, "enable the presence of the /proc/gvisor/kernel_is_gvisor file that can be used by applications to detect that gVisor is in use")
flagSet.String("override-procs", "", "comma-separated list of proc files to override with stubs (e.g. kallsyms)")

flagSet.Bool("ignore-cgroups", false, "don't configure cgroups.")
flagSet.Int("fdlimit", -1, "Specifies a limit on the number of host file descriptors that can be open. Applies separately to the sentry and gofer. Note: each file in the sandbox holds more than one host FD open.")
Expand Down
Loading