summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2018-09-07 12:27:44 -0700
committerShentubot <shentubot@google.com>2018-09-07 12:28:48 -0700
commitbc81f3fe4a042a15343d2eab44da32d818ac1ade (patch)
tree808e8e3ebfdf7e43b9f279032cd39e28fb75de98 /runsc/boot
parentf895cb4d8b4b37a563b7a5b9dc92eae552084b44 (diff)
Remove '--file-access=direct' option
It was used before gofer was implemented and it's not supported anymore. BREAKING CHANGE: proxy-shared and proxy-exclusive options are now: shared and exclusive. PiperOrigin-RevId: 212017643 Change-Id: If029d4073fe60583e5ca25f98abb2953de0d78fd
Diffstat (limited to 'runsc/boot')
-rw-r--r--runsc/boot/BUILD3
-rw-r--r--runsc/boot/config.go31
-rw-r--r--runsc/boot/filter/config.go39
-rw-r--r--runsc/boot/filter/filter.go5
-rw-r--r--runsc/boot/fs.go19
-rw-r--r--runsc/boot/loader.go1
-rw-r--r--runsc/boot/loader_test.go106
7 files changed, 75 insertions, 129 deletions
diff --git a/runsc/boot/BUILD b/runsc/boot/BUILD
index e96722069..a38a3a94e 100644
--- a/runsc/boot/BUILD
+++ b/runsc/boot/BUILD
@@ -85,8 +85,11 @@ go_test(
deps = [
"//pkg/control/server",
"//pkg/log",
+ "//pkg/p9",
"//pkg/sentry/context/contexttest",
"//pkg/sentry/fs",
+ "//pkg/unet",
+ "//runsc/fsgofer",
"@com_github_opencontainers_runtime-spec//specs-go:go_default_library",
],
)
diff --git a/runsc/boot/config.go b/runsc/boot/config.go
index 28a1600cd..01da535af 100644
--- a/runsc/boot/config.go
+++ b/runsc/boot/config.go
@@ -60,28 +60,23 @@ func (p PlatformType) String() string {
type FileAccessType int
const (
- // FileAccessProxy sends IO requests to a Gofer process that validates the
+ // FileAccessShared sends IO requests to a Gofer process that validates the
// requests and forwards them to the host.
- FileAccessProxy FileAccessType = iota
+ FileAccessShared FileAccessType = iota
- // FileAccessProxyExclusive is the same as FileAccessProxy, but enables
+ // FileAccessExclusive is the same as FileAccessShared, but enables
// extra caching for improved performance. It should only be used if
// the sandbox has exclusive access to the filesystem.
- FileAccessProxyExclusive
-
- // FileAccessDirect connects the sandbox directly to the host filesystem.
- FileAccessDirect
+ FileAccessExclusive
)
// MakeFileAccessType converts type from string.
func MakeFileAccessType(s string) (FileAccessType, error) {
switch s {
- case "proxy-shared":
- return FileAccessProxy, nil
- case "proxy-exclusive":
- return FileAccessProxyExclusive, nil
- case "direct":
- return FileAccessDirect, nil
+ case "shared":
+ return FileAccessShared, nil
+ case "exclusive":
+ return FileAccessExclusive, nil
default:
return 0, fmt.Errorf("invalid file access type %q", s)
}
@@ -89,12 +84,10 @@ func MakeFileAccessType(s string) (FileAccessType, error) {
func (f FileAccessType) String() string {
switch f {
- case FileAccessProxy:
- return "proxy-shared"
- case FileAccessProxyExclusive:
- return "proxy-exclusive"
- case FileAccessDirect:
- return "direct"
+ case FileAccessShared:
+ return "shared"
+ case FileAccessExclusive:
+ return "exclusive"
default:
return fmt.Sprintf("unknown(%d)", f)
}
diff --git a/runsc/boot/filter/config.go b/runsc/boot/filter/config.go
index f864b1f45..1a0c426ab 100644
--- a/runsc/boot/filter/config.go
+++ b/runsc/boot/filter/config.go
@@ -264,45 +264,6 @@ var allowedSyscalls = seccomp.SyscallRules{
},
}
-// whitelistFSFilters returns syscalls made by whitelistFS. Using WhitelistFS
-// is less secure because it runs inside the Sentry and must be able to perform
-// file operations that would otherwise be disabled by seccomp when a Gofer is
-// used. When whitelistFS is not used, openning new FD in the Sentry is
-// disallowed.
-func whitelistFSFilters() seccomp.SyscallRules {
- return seccomp.SyscallRules{
- syscall.SYS_ACCESS: {},
- syscall.SYS_FCHMOD: {},
- syscall.SYS_FSTAT: {},
- syscall.SYS_FSYNC: {},
- syscall.SYS_FTRUNCATE: {},
- syscall.SYS_GETCWD: {},
- syscall.SYS_GETDENTS: {},
- syscall.SYS_GETDENTS64: {},
- syscall.SYS_LSEEK: {},
- syscall.SYS_LSTAT: {},
- syscall.SYS_MKDIR: {},
- syscall.SYS_MKDIRAT: {},
- syscall.SYS_NEWFSTATAT: {},
- syscall.SYS_OPEN: {},
- syscall.SYS_OPENAT: {},
- syscall.SYS_PREAD64: {},
- syscall.SYS_PWRITE64: {},
- syscall.SYS_READ: {},
- syscall.SYS_READLINK: {},
- syscall.SYS_READLINKAT: {},
- syscall.SYS_RENAMEAT: {},
- syscall.SYS_STAT: {},
- syscall.SYS_SYMLINK: {},
- syscall.SYS_SYMLINKAT: {},
- syscall.SYS_SYNC_FILE_RANGE: {},
- syscall.SYS_UNLINK: {},
- syscall.SYS_UNLINKAT: {},
- syscall.SYS_UTIMENSAT: {},
- syscall.SYS_WRITE: {},
- }
-}
-
// hostInetFilters contains syscalls that are needed by sentry/socket/hostinet.
func hostInetFilters() seccomp.SyscallRules {
return seccomp.SyscallRules{
diff --git a/runsc/boot/filter/filter.go b/runsc/boot/filter/filter.go
index 56d30f2a0..b656883ad 100644
--- a/runsc/boot/filter/filter.go
+++ b/runsc/boot/filter/filter.go
@@ -30,7 +30,6 @@ import (
// Options are seccomp filter related options.
type Options struct {
Platform platform.Platform
- WhitelistFS bool
HostNetwork bool
ControllerFD int
}
@@ -44,10 +43,6 @@ func Install(opt Options) error {
// when not enabled.
s.Merge(instrumentationFilters())
- if opt.WhitelistFS {
- Report("direct file access allows unrestricted file access!")
- s.Merge(whitelistFSFilters())
- }
if opt.HostNetwork {
Report("host networking enabled: syscall filters less restrictive!")
s.Merge(hostInetFilters())
diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go
index 772df40fe..3df276170 100644
--- a/runsc/boot/fs.go
+++ b/runsc/boot/fs.go
@@ -204,7 +204,7 @@ func createRootMount(ctx context.Context, spec *specs.Spec, conf *Config, fds *f
)
switch conf.FileAccess {
- case FileAccessProxy, FileAccessProxyExclusive:
+ case FileAccessShared, FileAccessExclusive:
fd := fds.remove()
log.Infof("Mounting root over 9P, ioFD: %d", fd)
hostFS := mustFindFilesystem("9p")
@@ -214,13 +214,6 @@ func createRootMount(ctx context.Context, spec *specs.Spec, conf *Config, fds *f
return nil, fmt.Errorf("failed to generate root mount point: %v", err)
}
- case FileAccessDirect:
- hostFS := mustFindFilesystem("whitelistfs")
- rootInode, err = hostFS.Mount(ctx, rootDevice, mf, "root="+spec.Root.Path+",dont_translate_ownership=true")
- if err != nil {
- return nil, fmt.Errorf("failed to generate root mount point: %v", err)
- }
-
default:
return nil, fmt.Errorf("invalid file access type: %v", conf.FileAccess)
}
@@ -289,13 +282,10 @@ func getMountNameAndOptions(conf *Config, m specs.Mount, fds *fdDispenser) (stri
case bind:
switch conf.FileAccess {
- case FileAccessProxy, FileAccessProxyExclusive:
+ case FileAccessShared, FileAccessExclusive:
fd := fds.remove()
fsName = "9p"
opts = p9MountOptions(conf, fd)
- case FileAccessDirect:
- fsName = "whitelistfs"
- opts = []string{"root=" + m.Source, "dont_translate_ownership=true"}
default:
err = fmt.Errorf("invalid file access type: %v", conf.FileAccess)
}
@@ -423,7 +413,7 @@ func p9MountOptions(conf *Config, fd int) []string {
"wfdno=" + strconv.Itoa(fd),
"privateunixsocket=true",
}
- if conf.FileAccess == FileAccessProxy {
+ if conf.FileAccess == FileAccessShared {
opts = append(opts, "cache=remote_revalidating")
}
return opts
@@ -503,9 +493,6 @@ func addRestoreMount(conf *Config, renv *fs.RestoreEnvironment, m specs.Mount, f
// createRestoreEnvironment builds a fs.RestoreEnvironment called renv by adding the mounts
// to the environment.
func createRestoreEnvironment(spec *specs.Spec, conf *Config, fds *fdDispenser) (*fs.RestoreEnvironment, error) {
- if conf.FileAccess == FileAccessDirect {
- return nil, fmt.Errorf("host filesystem with whitelist not supported with S/R")
- }
renv := &fs.RestoreEnvironment{
MountSources: make(map[string][]fs.MountArgs),
}
diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go
index 540cd6188..5fb489766 100644
--- a/runsc/boot/loader.go
+++ b/runsc/boot/loader.go
@@ -341,7 +341,6 @@ func (l *Loader) run() error {
} else {
opts := filter.Options{
Platform: l.k.Platform,
- WhitelistFS: l.conf.FileAccess == FileAccessDirect,
HostNetwork: l.conf.Network == NetworkHost,
ControllerFD: l.ctrl.srv.FD(),
}
diff --git a/runsc/boot/loader_test.go b/runsc/boot/loader_test.go
index 2396d52c8..d6bfe9ff1 100644
--- a/runsc/boot/loader_test.go
+++ b/runsc/boot/loader_test.go
@@ -20,14 +20,18 @@ import (
"os"
"reflect"
"sync"
+ "syscall"
"testing"
"time"
specs "github.com/opencontainers/runtime-spec/specs-go"
"gvisor.googlesource.com/gvisor/pkg/control/server"
"gvisor.googlesource.com/gvisor/pkg/log"
+ "gvisor.googlesource.com/gvisor/pkg/p9"
"gvisor.googlesource.com/gvisor/pkg/sentry/context/contexttest"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
+ "gvisor.googlesource.com/gvisor/pkg/unet"
+ "gvisor.googlesource.com/gvisor/runsc/fsgofer"
)
func init() {
@@ -39,7 +43,6 @@ func testConfig() *Config {
return &Config{
RootDir: "unused_root_dir",
Network: NetworkNone,
- FileAccess: FileAccessDirect,
DisableSeccomp: true,
}
}
@@ -58,23 +61,62 @@ func testSpec() *specs.Spec {
}
}
-func createLoader() (*Loader, error) {
+// startGofer starts a new gofer routine serving 'root' path. It returns the
+// sandbox side of the connection, and a function that when called will stop the
+// gofer.
+func startGofer(root string) (int, func(), error) {
+ fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
+ if err != nil {
+ return 0, nil, err
+ }
+ sandboxEnd, goferEnd := fds[0], fds[1]
+
+ socket, err := unet.NewSocket(goferEnd)
+ if err != nil {
+ syscall.Close(sandboxEnd)
+ syscall.Close(goferEnd)
+ return 0, nil, fmt.Errorf("error creating server on FD %d: %v", goferEnd, err)
+ }
+ go func() {
+ at := fsgofer.NewAttachPoint(root, fsgofer.Config{ROMount: true})
+ s := p9.NewServer(at)
+ if err := s.Handle(socket); err != nil {
+ log.Infof("Gofer is stopping. FD: %d, err: %v\n", goferEnd, err)
+ }
+ }()
+ // Closing the gofer FD will stop the gofer and exit goroutine above.
+ return sandboxEnd, func() { syscall.Close(goferEnd) }, nil
+}
+
+func createLoader() (*Loader, func(), error) {
fd, err := server.CreateSocket(ControlSocketAddr(fmt.Sprintf("%010d", rand.Int())[:10]))
if err != nil {
- return nil, err
+ return nil, nil, err
}
conf := testConfig()
spec := testSpec()
- return New(spec, conf, fd, nil, false)
+
+ sandEnd, cleanup, err := startGofer(spec.Root.Path)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ l, err := New(spec, conf, fd, []int{sandEnd}, false)
+ if err != nil {
+ cleanup()
+ return nil, nil, err
+ }
+ return l, cleanup, nil
}
// TestRun runs a simple application in a sandbox and checks that it succeeds.
func TestRun(t *testing.T) {
- s, err := createLoader()
+ s, cleanup, err := createLoader()
if err != nil {
t.Fatalf("error creating loader: %v", err)
}
defer s.Destroy()
+ defer cleanup()
// Start a goroutine to read the start chan result, otherwise Run will
// block forever.
@@ -106,11 +148,12 @@ func TestRun(t *testing.T) {
// TestStartSignal tests that the controller Start message will cause
// WaitForStartSignal to return.
func TestStartSignal(t *testing.T) {
- s, err := createLoader()
+ s, cleanup, err := createLoader()
if err != nil {
t.Fatalf("error creating loader: %v", err)
}
defer s.Destroy()
+ defer cleanup()
// We aren't going to wait on this application, so the control server
// needs to be shut down manually.
@@ -330,7 +373,14 @@ func TestCreateMountNamespace(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
conf := testConfig()
ctx := contexttest.Context(t)
- mm, err := createMountNamespace(ctx, ctx, &tc.spec, conf, nil)
+
+ sandEnd, cleanup, err := startGofer(tc.spec.Root.Path)
+ if err != nil {
+ t.Fatalf("failed to create gofer: %v", err)
+ }
+ defer cleanup()
+
+ mm, err := createMountNamespace(ctx, ctx, &tc.spec, conf, []int{sandEnd})
if err != nil {
t.Fatalf("createMountNamespace test case %q failed: %v", tc.name, err)
}
@@ -352,7 +402,6 @@ func TestRestoreEnvironment(t *testing.T) {
testCases := []struct {
name string
spec *specs.Spec
- fileAccess FileAccessType
ioFDs []int
errorExpected bool
expectedRenv fs.RestoreEnvironment
@@ -375,7 +424,6 @@ func TestRestoreEnvironment(t *testing.T) {
},
},
},
- fileAccess: FileAccessProxy,
ioFDs: []int{0},
errorExpected: false,
expectedRenv: fs.RestoreEnvironment{
@@ -430,7 +478,6 @@ func TestRestoreEnvironment(t *testing.T) {
},
},
},
- fileAccess: FileAccessProxy,
ioFDs: []int{0, 1},
errorExpected: false,
expectedRenv: fs.RestoreEnvironment{
@@ -489,7 +536,6 @@ func TestRestoreEnvironment(t *testing.T) {
},
},
},
- fileAccess: FileAccessProxy,
ioFDs: []int{0},
errorExpected: false,
expectedRenv: fs.RestoreEnvironment{
@@ -534,48 +580,10 @@ func TestRestoreEnvironment(t *testing.T) {
},
},
},
- {
- name: "whitelist error test",
- spec: &specs.Spec{
- Root: &specs.Root{
- Path: os.TempDir(),
- Readonly: true,
- },
- Mounts: []specs.Mount{
- {
- Destination: "/dev/fd-foo",
- Type: "bind",
- },
- },
- },
- fileAccess: FileAccessDirect,
- ioFDs: []int{0, 1},
- errorExpected: true,
- },
- {
- name: "bad options test",
- spec: &specs.Spec{
- Root: &specs.Root{
- Path: os.TempDir(),
- Readonly: true,
- },
- Mounts: []specs.Mount{
- {
- Destination: "/dev/fd-foo",
- Type: "tmpfs",
- Options: []string{"invalid_option=true"},
- },
- },
- },
- fileAccess: FileAccessDirect,
- ioFDs: []int{0},
- errorExpected: true,
- },
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
conf := testConfig()
- conf.FileAccess = tc.fileAccess
fds := &fdDispenser{fds: tc.ioFDs}
actualRenv, err := createRestoreEnvironment(tc.spec, conf, fds)
if !tc.errorExpected && err != nil {