Add control configs
Also plumber the controls through runsc PiperOrigin-RevId: 391594318
This commit is contained in:
parent
e0bf522502
commit
75b5a4f455
|
@ -1,7 +1,13 @@
|
|||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
load("//tools:defs.bzl", "go_library", "go_test", "proto_library")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
proto_library(
|
||||
name = "control",
|
||||
srcs = ["control.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "control",
|
||||
srcs = [
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package gvisor;
|
||||
|
||||
// ControlConfig configures the permission of controls.
|
||||
message ControlConfig {
|
||||
// Names for individual control URPC service objects.
|
||||
// Any new service object that should be given conditional access should be
|
||||
// named here and conditionally added based on presence in allowed_controls.
|
||||
enum Endpoint {
|
||||
UNKNOWN = 0;
|
||||
EVENTS = 1;
|
||||
FS = 2;
|
||||
LIFECYCLE = 3;
|
||||
LOGGING = 4;
|
||||
PROFILE = 5;
|
||||
USAGE = 6;
|
||||
PROC = 7;
|
||||
STATE = 8;
|
||||
DEBUG = 9;
|
||||
}
|
||||
|
||||
// allowed_controls represents which endpoints may be registered to the
|
||||
// server.
|
||||
repeated Endpoint allowed_controls = 1;
|
||||
}
|
|
@ -45,6 +45,7 @@ go_library(
|
|||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/arch:registers_go_proto",
|
||||
"//pkg/sentry/control",
|
||||
"//pkg/sentry/control:control_go_proto",
|
||||
"//pkg/sentry/devices/memdev",
|
||||
"//pkg/sentry/devices/ttydev",
|
||||
"//pkg/sentry/devices/tundev",
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/fd"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/control"
|
||||
controlpb "gvisor.dev/gvisor/pkg/sentry/control/control_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/netstack"
|
||||
|
@ -165,15 +166,31 @@ func newController(fd int, l *Loader) (*controller, error) {
|
|||
ctrl.srv.Register(net)
|
||||
}
|
||||
|
||||
ctrl.srv.Register(&debug{})
|
||||
ctrl.srv.Register(&control.Events{})
|
||||
ctrl.srv.Register(&control.Logging{})
|
||||
ctrl.srv.Register(&control.Lifecycle{l.k})
|
||||
ctrl.srv.Register(&control.Fs{l.k})
|
||||
ctrl.srv.Register(&control.Usage{l.k})
|
||||
|
||||
if l.root.conf.ProfileEnable {
|
||||
ctrl.srv.Register(control.NewProfile(l.k))
|
||||
if l.root.conf.Controls.Controls != nil {
|
||||
for _, c := range l.root.conf.Controls.Controls.AllowedControls {
|
||||
switch c {
|
||||
case controlpb.ControlConfig_EVENTS:
|
||||
ctrl.srv.Register(&control.Events{})
|
||||
case controlpb.ControlConfig_FS:
|
||||
ctrl.srv.Register(&control.Fs{Kernel: l.k})
|
||||
case controlpb.ControlConfig_LIFECYCLE:
|
||||
ctrl.srv.Register(&control.Lifecycle{Kernel: l.k})
|
||||
case controlpb.ControlConfig_LOGGING:
|
||||
ctrl.srv.Register(&control.Logging{})
|
||||
case controlpb.ControlConfig_PROFILE:
|
||||
if l.root.conf.ProfileEnable {
|
||||
ctrl.srv.Register(control.NewProfile(l.k))
|
||||
}
|
||||
case controlpb.ControlConfig_USAGE:
|
||||
ctrl.srv.Register(&control.Usage{Kernel: l.k})
|
||||
case controlpb.ControlConfig_PROC:
|
||||
ctrl.srv.Register(&control.Proc{Kernel: l.k})
|
||||
case controlpb.ControlConfig_STATE:
|
||||
ctrl.srv.Register(&control.State{Kernel: l.k})
|
||||
case controlpb.ControlConfig_DEBUG:
|
||||
ctrl.srv.Register(&debug{})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ctrl, nil
|
||||
|
|
|
@ -11,6 +11,7 @@ go_library(
|
|||
visibility = ["//:sandbox"],
|
||||
deps = [
|
||||
"//pkg/refs",
|
||||
"//pkg/sentry/control:control_go_proto",
|
||||
"//pkg/sentry/watchdog",
|
||||
"//pkg/sync",
|
||||
"//runsc/flag",
|
||||
|
@ -24,5 +25,8 @@ go_test(
|
|||
"config_test.go",
|
||||
],
|
||||
library = ":config",
|
||||
deps = ["//runsc/flag"],
|
||||
deps = [
|
||||
"//pkg/sentry/control:control_go_proto",
|
||||
"//runsc/flag",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -19,8 +19,10 @@ package config
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
controlpb "gvisor.dev/gvisor/pkg/sentry/control/control_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/sentry/watchdog"
|
||||
)
|
||||
|
||||
|
@ -135,6 +137,9 @@ type Config struct {
|
|||
// ProfileEnable is set to prepare the sandbox to be profiled.
|
||||
ProfileEnable bool `flag:"profile"`
|
||||
|
||||
// Controls defines the controls that may be enabled.
|
||||
Controls controlConfig `flag:"controls"`
|
||||
|
||||
// RestoreFile is the path to the saved container image
|
||||
RestoreFile string
|
||||
|
||||
|
@ -351,6 +356,96 @@ func (q QueueingDiscipline) String() string {
|
|||
panic(fmt.Sprintf("Invalid qdisc %d", q))
|
||||
}
|
||||
|
||||
// controlConfig represents control endpoints.
|
||||
type controlConfig struct {
|
||||
Controls *controlpb.ControlConfig
|
||||
}
|
||||
|
||||
// Set implements flag.Value.
|
||||
func (c *controlConfig) Set(v string) error {
|
||||
controls := strings.Split(v, ",")
|
||||
var controlList []controlpb.ControlConfig_Endpoint
|
||||
for _, control := range controls {
|
||||
switch control {
|
||||
case "EVENTS":
|
||||
controlList = append(controlList, controlpb.ControlConfig_EVENTS)
|
||||
case "FS":
|
||||
controlList = append(controlList, controlpb.ControlConfig_FS)
|
||||
case "LIFECYCLE":
|
||||
controlList = append(controlList, controlpb.ControlConfig_LIFECYCLE)
|
||||
case "LOGGING":
|
||||
controlList = append(controlList, controlpb.ControlConfig_LOGGING)
|
||||
case "PROFILE":
|
||||
controlList = append(controlList, controlpb.ControlConfig_PROFILE)
|
||||
case "USAGE":
|
||||
controlList = append(controlList, controlpb.ControlConfig_USAGE)
|
||||
case "PROC":
|
||||
controlList = append(controlList, controlpb.ControlConfig_PROC)
|
||||
case "STATE":
|
||||
controlList = append(controlList, controlpb.ControlConfig_STATE)
|
||||
case "DEBUG":
|
||||
controlList = append(controlList, controlpb.ControlConfig_DEBUG)
|
||||
default:
|
||||
return fmt.Errorf("invalid control %q", control)
|
||||
}
|
||||
}
|
||||
c.Controls.AllowedControls = controlList
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get implements flag.Value.
|
||||
func (c *controlConfig) Get() interface{} {
|
||||
return *c
|
||||
}
|
||||
|
||||
// String implements flag.Value.
|
||||
func (c *controlConfig) String() string {
|
||||
v := ""
|
||||
for _, control := range c.Controls.AllowedControls {
|
||||
if len(v) > 0 {
|
||||
v += ","
|
||||
}
|
||||
switch control {
|
||||
case controlpb.ControlConfig_EVENTS:
|
||||
v += "EVENTS"
|
||||
case controlpb.ControlConfig_FS:
|
||||
v += "FS"
|
||||
case controlpb.ControlConfig_LIFECYCLE:
|
||||
v += "LIFECYCLE"
|
||||
case controlpb.ControlConfig_LOGGING:
|
||||
v += "LOGGING"
|
||||
case controlpb.ControlConfig_PROFILE:
|
||||
v += "PROFILE"
|
||||
case controlpb.ControlConfig_USAGE:
|
||||
v += "USAGE"
|
||||
case controlpb.ControlConfig_PROC:
|
||||
v += "PROC"
|
||||
case controlpb.ControlConfig_STATE:
|
||||
v += "STATE"
|
||||
case controlpb.ControlConfig_DEBUG:
|
||||
v += "DEBUG"
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid control %d", control))
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func defaultControlConfig() *controlConfig {
|
||||
c := controlConfig{}
|
||||
c.Controls = &controlpb.ControlConfig{}
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_EVENTS)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_FS)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_LIFECYCLE)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_LOGGING)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_PROFILE)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_USAGE)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_PROC)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_STATE)
|
||||
c.Controls.AllowedControls = append(c.Controls.AllowedControls, controlpb.ControlConfig_DEBUG)
|
||||
return &c
|
||||
}
|
||||
|
||||
func leakModePtr(v refs.LeakMode) *refs.LeakMode {
|
||||
return &v
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
controlpb "gvisor.dev/gvisor/pkg/sentry/control/control_go_proto"
|
||||
"gvisor.dev/gvisor/runsc/flag"
|
||||
)
|
||||
|
||||
|
@ -59,6 +60,9 @@ func TestFromFlags(t *testing.T) {
|
|||
if err := flag.CommandLine.Lookup("network").Value.Set("none"); err != nil {
|
||||
t.Errorf("Flag set: %v", err)
|
||||
}
|
||||
if err := flag.CommandLine.Lookup("controls").Value.Set("EVENTS,FS"); err != nil {
|
||||
t.Errorf("Flag set: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := setDefault("root"); err != nil {
|
||||
t.Errorf("Flag set: %v", err)
|
||||
|
@ -72,6 +76,9 @@ func TestFromFlags(t *testing.T) {
|
|||
if err := setDefault("network"); err != nil {
|
||||
t.Errorf("Flag set: %v", err)
|
||||
}
|
||||
if err := setDefault("controls"); err != nil {
|
||||
t.Errorf("Flag set: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
c, err := NewFromFlags()
|
||||
|
@ -90,6 +97,12 @@ func TestFromFlags(t *testing.T) {
|
|||
if want := NetworkNone; c.Network != want {
|
||||
t.Errorf("Network=%v, want: %v", c.Network, want)
|
||||
}
|
||||
wants := []controlpb.ControlConfig_Endpoint{controlpb.ControlConfig_EVENTS, controlpb.ControlConfig_FS}
|
||||
for i, want := range wants {
|
||||
if c.Controls.Controls.AllowedControls[i] != want {
|
||||
t.Errorf("Controls.Controls.AllowedControls[%d]=%v, want: %v", i, c.Controls.Controls.AllowedControls[i], want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToFlags(t *testing.T) {
|
||||
|
@ -101,10 +114,15 @@ func TestToFlags(t *testing.T) {
|
|||
c.Debug = true
|
||||
c.NumNetworkChannels = 123
|
||||
c.Network = NetworkNone
|
||||
c.Controls = controlConfig{
|
||||
Controls: &controlpb.ControlConfig{
|
||||
AllowedControls: []controlpb.ControlConfig_Endpoint{controlpb.ControlConfig_EVENTS, controlpb.ControlConfig_FS},
|
||||
},
|
||||
}
|
||||
|
||||
flags := c.ToFlags()
|
||||
if len(flags) != 4 {
|
||||
t.Errorf("wrong number of flags set, want: 4, got: %d: %s", len(flags), flags)
|
||||
if len(flags) != 5 {
|
||||
t.Errorf("wrong number of flags set, want: 5, got: %d: %s", len(flags), flags)
|
||||
}
|
||||
t.Logf("Flags: %s", flags)
|
||||
fm := map[string]string{}
|
||||
|
@ -117,6 +135,7 @@ func TestToFlags(t *testing.T) {
|
|||
"--debug": "true",
|
||||
"--num-network-channels": "123",
|
||||
"--network": "none",
|
||||
"--controls": "EVENTS,FS",
|
||||
} {
|
||||
if got, ok := fm[name]; ok {
|
||||
if got != want {
|
||||
|
|
|
@ -67,6 +67,7 @@ func RegisterFlags() {
|
|||
flag.Var(leakModePtr(refs.NoLeakChecking), "ref-leak-mode", "sets reference leak check mode: disabled (default), log-names, log-traces.")
|
||||
flag.Bool("cpu-num-from-quota", false, "set cpu number to cpu quota (least integer greater or equal to quota value, but not less than 2)")
|
||||
flag.Bool("oci-seccomp", false, "Enables loading OCI seccomp filters inside the sandbox.")
|
||||
flag.Var(defaultControlConfig(), "controls", "Sentry control endpoints.")
|
||||
|
||||
// Flags that control sandbox runtime behavior: FS related.
|
||||
flag.Var(fileAccessTypePtr(FileAccessExclusive), "file-access", "specifies which filesystem validation to use for the root mount: exclusive (default), shared.")
|
||||
|
|
Loading…
Reference in New Issue