diff --git a/pkg/sentry/fsimpl/testutil/kernel.go b/pkg/sentry/fsimpl/testutil/kernel.go index b6027583f..2df2501ee 100644 --- a/pkg/sentry/fsimpl/testutil/kernel.go +++ b/pkg/sentry/fsimpl/testutil/kernel.go @@ -44,7 +44,8 @@ import ( ) var ( - platformFlag = flag.String("platform", "ptrace", "specify which platform to use") + platformFlag = flag.String("platform", "ptrace", "specify which platform to use") + platformDevicePathFlag = flag.String("platform_device_path", "", "path to a platform-specific device file (e.g. /dev/kvm for KVM platform). If unset, will use a sane platform-specific default.") ) // Boot initializes a new bare bones kernel for test. @@ -53,7 +54,7 @@ func Boot() (*kernel.Kernel, error) { if err != nil { return nil, fmt.Errorf("platform not found: %v", err) } - deviceFile, err := platformCtr.OpenDevice() + deviceFile, err := platformCtr.OpenDevice(*platformDevicePathFlag) if err != nil { return nil, fmt.Errorf("creating platform: %v", err) } diff --git a/pkg/sentry/platform/kvm/kvm.go b/pkg/sentry/platform/kvm/kvm.go index 0d6490fa6..20caddb89 100644 --- a/pkg/sentry/platform/kvm/kvm.go +++ b/pkg/sentry/platform/kvm/kvm.go @@ -76,15 +76,15 @@ var ( globalErr error ) -// OpenDevice opens the KVM device at /dev/kvm and returns the File. -func OpenDevice() (*os.File, error) { - dev, ok := os.LookupEnv("GVISOR_KVM_DEV") - if !ok { - dev = "/dev/kvm" +// OpenDevice opens the KVM device and returns the File. +// If the devicePath is empty, it will default to /dev/kvm. +func OpenDevice(devicePath string) (*os.File, error) { + if devicePath == "" { + devicePath = "/dev/kvm" } - f, err := os.OpenFile(dev, unix.O_RDWR, 0) + f, err := os.OpenFile(devicePath, unix.O_RDWR, 0) if err != nil { - return nil, fmt.Errorf("error opening KVM device file (%s): %v", dev, err) + return nil, fmt.Errorf("error opening KVM device file (%s): %v", devicePath, err) } return f, nil } @@ -186,8 +186,8 @@ func (*constructor) New(f *os.File) (platform.Platform, error) { return New(f) } -func (*constructor) OpenDevice() (*os.File, error) { - return OpenDevice() +func (*constructor) OpenDevice(devicePath string) (*os.File, error) { + return OpenDevice(devicePath) } // Flags implements platform.Constructor.Flags(). diff --git a/pkg/sentry/platform/kvm/kvm_test.go b/pkg/sentry/platform/kvm/kvm_test.go index 2ed9cf766..36ec9aa63 100644 --- a/pkg/sentry/platform/kvm/kvm_test.go +++ b/pkg/sentry/platform/kvm/kvm_test.go @@ -42,7 +42,7 @@ type testHarness interface { func kvmTest(t testHarness, setup func(*KVM), fn func(*vCPU) bool) { // Create the machine. - deviceFile, err := OpenDevice() + deviceFile, err := OpenDevice("") if err != nil { t.Fatalf("error opening device file: %v", err) } diff --git a/pkg/sentry/platform/platform.go b/pkg/sentry/platform/platform.go index 679d6fd8f..96900a322 100644 --- a/pkg/sentry/platform/platform.go +++ b/pkg/sentry/platform/platform.go @@ -426,7 +426,11 @@ type Constructor interface { // // * deviceFile - the device file (e.g. /dev/kvm for the KVM platform). New(deviceFile *os.File) (Platform, error) - OpenDevice() (*os.File, error) + + // OpenDevice opens the path to the device used by the platform. + // Passing in an empty string will use the default path for the device, + // e.g. "/dev/kvm" for the KVM platform. + OpenDevice(devicePath string) (*os.File, error) // Requirements returns platform specific requirements. Requirements() Requirements diff --git a/pkg/sentry/platform/ptrace/ptrace.go b/pkg/sentry/platform/ptrace/ptrace.go index 424a12a3c..2566679c4 100644 --- a/pkg/sentry/platform/ptrace/ptrace.go +++ b/pkg/sentry/platform/ptrace/ptrace.go @@ -262,7 +262,7 @@ func (*constructor) New(*os.File) (platform.Platform, error) { return New() } -func (*constructor) OpenDevice() (*os.File, error) { +func (*constructor) OpenDevice(_ string) (*os.File, error) { return nil, nil } diff --git a/runsc/cmd/install.go b/runsc/cmd/install.go index 69cb75d62..757b829d8 100644 --- a/runsc/cmd/install.go +++ b/runsc/cmd/install.go @@ -78,7 +78,7 @@ func (i *Install) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) if err != nil { log.Fatalf("invalid platform: %v", err) } - deviceFile, err := p.OpenDevice() + deviceFile, err := p.OpenDevice(conf.PlatformDevicePath) if err != nil { log.Printf("WARNING: unable to open platform, runsc may fail to start: %v", err) } diff --git a/runsc/config/config.go b/runsc/config/config.go index 3f34d5639..3649cd6bc 100644 --- a/runsc/config/config.go +++ b/runsc/config/config.go @@ -114,6 +114,11 @@ type Config struct { // Platform is the platform to run on. Platform string `flag:"platform"` + // PlatformDevicePath is the path to the device file used by the platform. + // e.g. "/dev/kvm" for the KVM platform. + // If unset, a sane platform-specific default will be used. + PlatformDevicePath string `flag:"platform_device_path"` + // Strace indicates that strace should be enabled. Strace bool `flag:"strace"` diff --git a/runsc/config/flags.go b/runsc/config/flags.go index be0b1ac97..6bc725161 100644 --- a/runsc/config/flags.go +++ b/runsc/config/flags.go @@ -56,6 +56,7 @@ func RegisterFlags(flagSet *flag.FlagSet) { // Flags that control sandbox runtime behavior. flagSet.String("platform", "ptrace", "specifies which platform to use: ptrace (default), kvm.") + flagSet.String("platform_device_path", "", "path to a platform-specific device file (e.g. /dev/kvm for KVM platform). If unset, will use a sane platform-specific default.") flagSet.Var(watchdogActionPtr(watchdog.LogWarning), "watchdog-action", "sets what action the watchdog takes when triggered: log (default), panic.") flagSet.Int("panic-signal", -1, "register signal handling that panics. Usually set to SIGUSR2(12) to troubleshoot hangs. -1 disables it.") flagSet.Bool("profile", false, "prepares the sandbox to use Golang profiler. Note that enabling profiler loosens the seccomp protection added to the sandbox (DO NOT USE IN PRODUCTION).") diff --git a/runsc/sandbox/sandbox.go b/runsc/sandbox/sandbox.go index 4ecb3887a..8b59fa512 100644 --- a/runsc/sandbox/sandbox.go +++ b/runsc/sandbox/sandbox.go @@ -322,7 +322,7 @@ func (s *Sandbox) Restore(cid string, spec *specs.Spec, conf *config.Config, fil } // If the platform needs a device FD we must pass it in. - if deviceFile, err := deviceFileForPlatform(conf.Platform); err != nil { + if deviceFile, err := deviceFileForPlatform(conf.Platform, conf.PlatformDevicePath); err != nil { return err } else if deviceFile != nil { defer deviceFile.Close() @@ -596,7 +596,7 @@ func (s *Sandbox) createSandboxProcess(conf *config.Config, args *Args, startSyn return err } - if deviceFile, err := gPlatform.OpenDevice(); err != nil { + if deviceFile, err := gPlatform.OpenDevice(conf.PlatformDevicePath); err != nil { return fmt.Errorf("opening device file for platform %q: %v", conf.Platform, err) } else if deviceFile != nil { defer deviceFile.Close() @@ -1407,13 +1407,14 @@ func (s *Sandbox) configureStdios(conf *config.Config, stdios []*os.File) error // deviceFileForPlatform opens the device file for the given platform. If the // platform does not need a device file, then nil is returned. -func deviceFileForPlatform(name string) (*os.File, error) { +// devicePath may be empty to use a sane platform-specific default. +func deviceFileForPlatform(name, devicePath string) (*os.File, error) { p, err := platform.Lookup(name) if err != nil { return nil, err } - f, err := p.OpenDevice() + f, err := p.OpenDevice(devicePath) if err != nil { return nil, fmt.Errorf("opening device file for platform %q: %w", name, err) }