diff --git a/drivers/docker/config.go b/drivers/docker/config.go index ec919360d41..898d9172c87 100644 --- a/drivers/docker/config.go +++ b/drivers/docker/config.go @@ -10,6 +10,7 @@ import ( docker "github.com/fsouza/go-dockerclient" "github.com/hashicorp/go-hclog" + "github.com/hashicorp/nomad/drivers/shared/capabilities" "github.com/hashicorp/nomad/helper/pluginutils/hclutils" "github.com/hashicorp/nomad/helper/pluginutils/loader" "github.com/hashicorp/nomad/plugins/base" @@ -287,7 +288,7 @@ var ( "allow_privileged": hclspec.NewAttr("allow_privileged", "bool", false), "allow_caps": hclspec.NewDefault( hclspec.NewAttr("allow_caps", "list(string)", false), - hclspec.NewLiteral(`["CHOWN","DAC_OVERRIDE","FSETID","FOWNER","MKNOD","SETGID","SETUID","SETFCAP","SETPCAP","NET_BIND_SERVICE","SYS_CHROOT","KILL","AUDIT_WRITE"]`), + hclspec.NewLiteral(capabilities.HCLSpecLiteral), ), "nvidia_runtime": hclspec.NewDefault( hclspec.NewAttr("nvidia_runtime", "string", false), @@ -427,9 +428,9 @@ var ( "work_dir": hclspec.NewAttr("work_dir", "string", false), }) - // capabilities is returned by the Capabilities RPC and indicates what - // optional features this driver supports - capabilities = &drivers.Capabilities{ + // driverCapabilities represents the RPC response for what features are + // implemented by the docker task driver + driverCapabilities = &drivers.Capabilities{ SendSignals: true, Exec: true, FSIsolation: drivers.FSIsolationImage, @@ -788,8 +789,10 @@ func (d *Driver) TaskConfigSchema() (*hclspec.Spec, error) { return taskConfigSpec, nil } +// Capabilities is returned by the Capabilities RPC and indicates what optional +// features this driver supports. func (d *Driver) Capabilities() (*drivers.Capabilities, error) { - return capabilities, nil + return driverCapabilities, nil } var _ drivers.InternalCapabilitiesDriver = (*Driver)(nil) diff --git a/drivers/exec/driver.go b/drivers/exec/driver.go index b7cfb0058db..4357965083c 100644 --- a/drivers/exec/driver.go +++ b/drivers/exec/driver.go @@ -10,6 +10,7 @@ import ( "time" "github.com/hashicorp/nomad/client/lib/cgutil" + "github.com/hashicorp/nomad/drivers/shared/capabilities" "github.com/hashicorp/consul-template/signals" hclog "github.com/hashicorp/go-hclog" @@ -74,6 +75,10 @@ var ( hclspec.NewAttr("default_ipc_mode", "string", false), hclspec.NewLiteral(`"private"`), ), + "allow_caps": hclspec.NewDefault( + hclspec.NewAttr("allow_caps", "list(string)", false), + hclspec.NewLiteral(capabilities.HCLSpecLiteral), + ), }) // taskConfigSpec is the hcl specification for the driver config section of @@ -83,11 +88,13 @@ var ( "args": hclspec.NewAttr("args", "list(string)", false), "pid_mode": hclspec.NewAttr("pid_mode", "string", false), "ipc_mode": hclspec.NewAttr("ipc_mode", "string", false), + "cap_add": hclspec.NewAttr("cap_add", "list(string)", false), + "cap_drop": hclspec.NewAttr("cap_drop", "list(string)", false), }) - // capabilities is returned by the Capabilities RPC and indicates what - // optional features this driver supports - capabilities = &drivers.Capabilities{ + // driverCapabilities represents the RPC response for what features are + // implemented by the exec task driver + driverCapabilities = &drivers.Capabilities{ SendSignals: true, Exec: true, FSIsolation: drivers.FSIsolationChroot, @@ -141,6 +148,10 @@ type Config struct { // DefaultModeIPC is the default IPC isolation set for all tasks using // exec-based task drivers. DefaultModeIPC string `codec:"default_ipc_mode"` + + // AllowCaps configures which Linux Capabilities are enabled for tasks + // running on this node. + AllowCaps []string `codec:"allow_caps"` } func (c *Config) validate() error { @@ -156,6 +167,11 @@ func (c *Config) validate() error { return fmt.Errorf("default_ipc_mode must be %q or %q, got %q", executor.IsolationModePrivate, executor.IsolationModeHost, c.DefaultModeIPC) } + badCaps := capabilities.Supported().Difference(capabilities.New(c.AllowCaps)) + if !badCaps.Empty() { + return fmt.Errorf("allow_caps configured with capabilities not supported by system: %s", badCaps) + } + return nil } @@ -174,6 +190,12 @@ type TaskConfig struct { // ModeIPC indicates whether IPC namespace isolation is enabled for the task. // Must be "private" or "host" if set. ModeIPC string `codec:"ipc_mode"` + + // CapAdd is a set of linux capabilities to enable. + CapAdd []string `codec:"cap_add"` + + // CapDrop is a set of linux capabilities to disable. + CapDrop []string `codec:"cap_drop"` } func (tc *TaskConfig) validate() error { @@ -189,6 +211,16 @@ func (tc *TaskConfig) validate() error { return fmt.Errorf("ipc_mode must be %q or %q, got %q", executor.IsolationModePrivate, executor.IsolationModeHost, tc.ModeIPC) } + supported := capabilities.Supported() + badAdds := supported.Difference(capabilities.New(tc.CapAdd)) + if !badAdds.Empty() { + return fmt.Errorf("cap_add configured with capabilities not supported by system: %s", badAdds) + } + badDrops := supported.Difference(capabilities.New(tc.CapDrop)) + if !badDrops.Empty() { + return fmt.Errorf("cap_drop configured with capabilities not supported by system: %s", badDrops) + } + return nil } @@ -266,8 +298,33 @@ func (d *Driver) TaskConfigSchema() (*hclspec.Spec, error) { return taskConfigSpec, nil } +// getCaps computes the complete set of linux capabilities to enable for driver, +// which gets passed along to libcontainer. +func (d *Driver) getCaps(tc *TaskConfig) ([]string, error) { + driverAllowed := capabilities.New(d.config.AllowCaps) + + // determine caps the task wants that are not allowed + taskCaps := capabilities.New(tc.CapAdd) + missing := driverAllowed.Difference(taskCaps) + if !missing.Empty() { + return nil, fmt.Errorf("driver does not allow the following capabilities: %s", missing) + } + + // if task did not specify allowed caps, use nomad defaults minus task drops + if len(tc.CapAdd) == 0 { + driverAllowed.Remove(tc.CapDrop) + return driverAllowed.Slice(true), nil + } + + // otherwise task did specify allowed caps, enable exactly those + taskAdd := capabilities.New(tc.CapAdd) + return taskAdd.Slice(true), nil +} + +// Capabilities is returned by the Capabilities RPC and indicates what +// optional features this driver supports func (d *Driver) Capabilities() (*drivers.Capabilities, error) { - return capabilities, nil + return driverCapabilities, nil } func (d *Driver) Fingerprint(ctx context.Context) (<-chan *drivers.Fingerprint, error) { @@ -439,6 +496,11 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive cfg.Mounts = append(cfg.Mounts, dnsMount) } + caps, err := d.getCaps(&driverConfig) + if err != nil { + return nil, nil, err + } + execCmd := &executor.ExecCommand{ Cmd: driverConfig.Command, Args: driverConfig.Args, @@ -455,6 +517,7 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive NetworkIsolation: cfg.NetworkIsolation, ModePID: executor.IsolationMode(d.config.DefaultModePID, driverConfig.ModePID), ModeIPC: executor.IsolationMode(d.config.DefaultModeIPC, driverConfig.ModeIPC), + Capabilities: caps, } ps, err := exec.Launch(execCmd) @@ -482,7 +545,7 @@ func (d *Driver) StartTask(cfg *drivers.TaskConfig) (*drivers.TaskHandle, *drive if err := handle.SetDriverState(&driverState); err != nil { d.logger.Error("failed to start task, error setting driver state", "error", err) - exec.Shutdown("", 0) + _ = exec.Shutdown("", 0) pluginClient.Kill() return nil, nil, fmt.Errorf("failed to set driver state: %v", err) } diff --git a/drivers/exec/driver_test.go b/drivers/exec/driver_test.go index be5dda5cf4c..8651eda20d2 100644 --- a/drivers/exec/driver_test.go +++ b/drivers/exec/driver_test.go @@ -764,42 +764,99 @@ func TestExecDriver_NoPivotRoot(t *testing.T) { } func TestDriver_Config_validate(t *testing.T) { - for _, tc := range []struct { - pidMode, ipcMode string - exp error - }{ - {pidMode: "host", ipcMode: "host", exp: nil}, - {pidMode: "private", ipcMode: "host", exp: nil}, - {pidMode: "host", ipcMode: "private", exp: nil}, - {pidMode: "private", ipcMode: "private", exp: nil}, - {pidMode: "other", ipcMode: "private", exp: errors.New(`default_pid_mode must be "private" or "host", got "other"`)}, - {pidMode: "private", ipcMode: "other", exp: errors.New(`default_ipc_mode must be "private" or "host", got "other"`)}, - } { - require.Equal(t, tc.exp, (&Config{ - DefaultModePID: tc.pidMode, - DefaultModeIPC: tc.ipcMode, - }).validate()) - } + t.Run("pid/ipc", func(t *testing.T) { + for _, tc := range []struct { + pidMode, ipcMode string + exp error + }{ + {pidMode: "host", ipcMode: "host", exp: nil}, + {pidMode: "private", ipcMode: "host", exp: nil}, + {pidMode: "host", ipcMode: "private", exp: nil}, + {pidMode: "private", ipcMode: "private", exp: nil}, + {pidMode: "other", ipcMode: "private", exp: errors.New(`default_pid_mode must be "private" or "host", got "other"`)}, + {pidMode: "private", ipcMode: "other", exp: errors.New(`default_ipc_mode must be "private" or "host", got "other"`)}, + } { + require.Equal(t, tc.exp, (&Config{ + DefaultModePID: tc.pidMode, + DefaultModeIPC: tc.ipcMode, + }).validate()) + } + }) + + t.Run("allow_caps", func(t *testing.T) { + for _, tc := range []struct { + ac []string + exp error + }{ + {ac: []string{}, exp: nil}, + {ac: []string{"all"}, exp: nil}, + {ac: []string{"chown", "sys_time"}, exp: nil}, + {ac: []string{"CAP_CHOWN", "cap_sys_time"}, exp: nil}, + {ac: []string{"chown", "not_valid", "sys_time"}, exp: errors.New("allow_caps configured with capabilities not supported by system: not_valid")}, + } { + require.Equal(t, tc.exp, (&Config{ + DefaultModePID: "private", + DefaultModeIPC: "private", + AllowCaps: tc.ac, + }).validate()) + } + }) } func TestDriver_TaskConfig_validate(t *testing.T) { - for _, tc := range []struct { - pidMode, ipcMode string - exp error - }{ - {pidMode: "host", ipcMode: "host", exp: nil}, - {pidMode: "host", ipcMode: "private", exp: nil}, - {pidMode: "host", ipcMode: "", exp: nil}, - {pidMode: "host", ipcMode: "other", exp: errors.New(`ipc_mode must be "private" or "host", got "other"`)}, - - {pidMode: "host", ipcMode: "host", exp: nil}, - {pidMode: "private", ipcMode: "host", exp: nil}, - {pidMode: "", ipcMode: "host", exp: nil}, - {pidMode: "other", ipcMode: "host", exp: errors.New(`pid_mode must be "private" or "host", got "other"`)}, - } { - require.Equal(t, tc.exp, (&TaskConfig{ - ModePID: tc.pidMode, - ModeIPC: tc.ipcMode, - }).validate()) - } + t.Run("pid/ipc", func(t *testing.T) { + for _, tc := range []struct { + pidMode, ipcMode string + exp error + }{ + {pidMode: "host", ipcMode: "host", exp: nil}, + {pidMode: "host", ipcMode: "private", exp: nil}, + {pidMode: "host", ipcMode: "", exp: nil}, + {pidMode: "host", ipcMode: "other", exp: errors.New(`ipc_mode must be "private" or "host", got "other"`)}, + + {pidMode: "host", ipcMode: "host", exp: nil}, + {pidMode: "private", ipcMode: "host", exp: nil}, + {pidMode: "", ipcMode: "host", exp: nil}, + {pidMode: "other", ipcMode: "host", exp: errors.New(`pid_mode must be "private" or "host", got "other"`)}, + } { + require.Equal(t, tc.exp, (&TaskConfig{ + ModePID: tc.pidMode, + ModeIPC: tc.ipcMode, + }).validate()) + } + }) + + t.Run("cap_add", func(t *testing.T) { + for _, tc := range []struct { + adds []string + exp error + }{ + {adds: nil, exp: nil}, + {adds: []string{"chown"}, exp: nil}, + {adds: []string{"CAP_CHOWN"}, exp: nil}, + {adds: []string{"chown", "sys_time"}, exp: nil}, + {adds: []string{"chown", "not_valid", "sys_time"}, exp: errors.New("cap_add configured with capabilities not supported by system: not_valid")}, + } { + require.Equal(t, tc.exp, (&TaskConfig{ + CapAdd: tc.adds, + }).validate()) + } + }) + + t.Run("cap_drop", func(t *testing.T) { + for _, tc := range []struct { + drops []string + exp error + }{ + {drops: nil, exp: nil}, + {drops: []string{"chown"}, exp: nil}, + {drops: []string{"CAP_CHOWN"}, exp: nil}, + {drops: []string{"chown", "sys_time"}, exp: nil}, + {drops: []string{"chown", "not_valid", "sys_time"}, exp: errors.New("cap_drop configured with capabilities not supported by system: not_valid")}, + } { + require.Equal(t, tc.exp, (&TaskConfig{ + CapDrop: tc.drops, + }).validate()) + } + }) } diff --git a/drivers/exec/driver_unix_test.go b/drivers/exec/driver_unix_test.go index f8d77a2d7a1..3b2e60374aa 100644 --- a/drivers/exec/driver_unix_test.go +++ b/drivers/exec/driver_unix_test.go @@ -5,9 +5,13 @@ package exec import ( "context" "fmt" + "strings" "testing" "time" + "github.com/hashicorp/nomad/drivers/shared/capabilities" + "github.com/hashicorp/nomad/drivers/shared/executor" + basePlug "github.com/hashicorp/nomad/plugins/base" "github.com/stretchr/testify/require" "golang.org/x/sys/unix" @@ -173,5 +177,128 @@ func TestExec_dnsConfig(t *testing.T) { dtestutil.TestTaskDNSConfig(t, harness, task.ID, c.cfg) } +} + +func TestExecDriver_Capabilities(t *testing.T) { + ctestutils.ExecCompatible(t) + + task := &drivers.TaskConfig{ + ID: uuid.Generate(), + Name: "sleep", + } + for _, tc := range []struct { + Name string + CapAdd []string + CapDrop []string + AllowList string + StartError string + }{ + { + Name: "default-allowlist-add-allowed", + CapAdd: []string{"fowner", "mknod"}, + CapDrop: []string{"ALL"}, + }, + { + Name: "default-allowlist-add-forbidden", + CapAdd: []string{"net_admin"}, + StartError: "net_admin", + }, + { + Name: "default-allowlist-drop-existing", + CapDrop: []string{"FOWNER", "MKNOD", "NET_RAW"}, + }, + { + Name: "restrictive-allowlist-drop-all", + CapDrop: []string{"ALL"}, + AllowList: "FOWNER,MKNOD", + }, + { + Name: "restrictive-allowlist-add-allowed", + CapAdd: []string{"fowner", "mknod"}, + CapDrop: []string{"ALL"}, + AllowList: "fowner,mknod", + }, + { + Name: "restrictive-allowlist-add-forbidden", + CapAdd: []string{"net_admin", "mknod"}, + CapDrop: []string{"ALL"}, + AllowList: "fowner,mknod", + StartError: "net_admin", + }, + { + Name: "restrictive-allowlist-add-multiple-forbidden", + CapAdd: []string{"net_admin", "mknod", "CAP_SYS_TIME"}, + CapDrop: []string{"ALL"}, + AllowList: "fowner,mknod", + StartError: "net_admin, sys_time", + }, + { + Name: "permissive-allowlist", + CapAdd: []string{"net_admin", "mknod"}, + AllowList: "ALL", + }, + { + Name: "permissive-allowlist-add-all", + CapAdd: []string{"all"}, + AllowList: "ALL", + }, + } { + t.Run(tc.Name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + d := NewExecDriver(ctx, testlog.HCLogger(t)) + harness := dtestutil.NewDriverHarness(t, d) + defer harness.Kill() + + config := &Config{ + NoPivotRoot: true, + DefaultModePID: executor.IsolationModePrivate, + DefaultModeIPC: executor.IsolationModePrivate, + } + + if tc.AllowList != "" { + config.AllowCaps = strings.Split(tc.AllowList, ",") + } else { + // inherit HCL defaults if not set + config.AllowCaps = capabilities.NomadDefaults().Slice(true) + } + + var data []byte + require.NoError(t, basePlug.MsgPackEncode(&data, config)) + baseConfig := &basePlug.Config{PluginConfig: data} + require.NoError(t, harness.SetConfig(baseConfig)) + + cleanup := harness.MkAllocDir(task, false) + defer cleanup() + + tCfg := &TaskConfig{ + Command: "/bin/sleep", + Args: []string{"9000"}, + } + if len(tc.CapAdd) > 0 { + tCfg.CapAdd = tc.CapAdd + } + if len(tc.CapDrop) > 0 { + tCfg.CapDrop = tc.CapDrop + } + require.NoError(t, task.EncodeConcreteDriverConfig(&tCfg)) + + // check the start error against expectations + _, _, err := harness.StartTask(task) + if err == nil && tc.StartError != "" { + t.Fatalf("Expected error in start: %v", tc.StartError) + } else if err != nil { + if tc.StartError == "" { + require.NoError(t, err) + } else { + require.Contains(t, err.Error(), tc.StartError) + } + return + } + + _ = d.DestroyTask(task.ID, true) + }) + } } diff --git a/drivers/shared/capabilities/defaults.go b/drivers/shared/capabilities/defaults.go new file mode 100644 index 00000000000..a1a6e3531e0 --- /dev/null +++ b/drivers/shared/capabilities/defaults.go @@ -0,0 +1,114 @@ +package capabilities + +import ( + "regexp" + + "github.com/syndtr/gocapability/capability" +) + +const ( + // HCLSpecLiteral is an equivalent list to NomadDefaults, expressed as a literal + // HCL string for use in HCL config parsing. + HCLSpecLiteral = `["AUDIT_WRITE","CHOWN","DAC_OVERRIDE","FOWNER","FSETID","KILL","MKNOD","NET_BIND_SERVICE","SETFCAP","SETGID","SETPCAP","SETUID","SYS_CHROOT"]` +) + +var ( + extractLiteral = regexp.MustCompile(`("[\w]+)`) +) + +// NomadDefaults is the set of Linux capabilities that Nomad enables by +// default. This list originates from what Docker enabled by default, but then +// excludes NET_RAW for security reasons. +// +// This set is use in the as HCL configuration default, described by HCLSpecLiteral. +func NomadDefaults() *Set { + return New(extractLiteral.FindAllString(HCLSpecLiteral, -1)) +} + +// DockerDefaults is a list of Linux capabilities enabled by Docker by default +// and is used to compute the set of capabilities to add/drop given docker driver +// configuration. +// +// https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities +func DockerDefaults() *Set { + defaults := NomadDefaults() + defaults.Add("NET_RAW") + return defaults +} + +// Supported returns the set of capabilities supported by the operating system. +// +// Defers to a library generated from +// https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h +func Supported() *Set { + s := New(nil) + + last := capability.CAP_LAST_CAP + + // workaround for RHEL6 which has no /proc/sys/kernel/cap_last_cap + if last == capability.Cap(63) { + last = capability.CAP_BLOCK_SUSPEND + } + + // accumulate every capability supported by this system + for _, c := range capability.List() { + if c > last { + continue + } + s.Add(c.String()) + } + + return s +} + +// LegacySupported returns the historical set of capabilities used when a task is +// configured to run as root using the exec task driver. Older versions of Nomad +// always allowed the root user to make use of any capability. Now that the exec +// task driver supports configuring the allowed capabilities, operators are +// encouraged to explicitly opt-in to capabilities beyond this legacy set. We +// maintain the legacy list here, because previous versions of Nomad deferred to +// the capability.List library function, which adds new capabilities over time. +// +// https://github.com/hashicorp/nomad/blob/v1.0.4/vendor/github.com/syndtr/gocapability/capability/enum_gen.go#L88 +func LegacySupported() *Set { + return New([]string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_KILL", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETPCAP", + "CAP_LINUX_IMMUTABLE", + "CAP_NET_BIND_SERVICE", + "CAP_NET_BROADCAST", + "CAP_NET_ADMIN", + "CAP_NET_RAW", + "CAP_IPC_LOCK", + "CAP_IPC_OWNER", + "CAP_SYS_MODULE", + "CAP_SYS_RAWIO", + "CAP_SYS_CHROOT", + "CAP_SYS_PTRACE", + "CAP_SYS_PACCT", + "CAP_SYS_ADMIN", + "CAP_SYS_BOOT", + "CAP_SYS_NICE", + "CAP_SYS_RESOURCE", + "CAP_SYS_TIME", + "CAP_SYS_TTY_CONFIG", + "CAP_MKNOD", + "CAP_LEASE", + "CAP_AUDIT_WRITE", + "CAP_AUDIT_CONTROL", + "CAP_SETFCAP", + "CAP_MAC_OVERRIDE", + "CAP_MAC_ADMIN", + "CAP_SYSLOG", + "CAP_WAKE_ALARM", + "CAP_BLOCK_SUSPEND", + "CAP_AUDIT_READ", + }) +} diff --git a/drivers/shared/capabilities/defaults_test.go b/drivers/shared/capabilities/defaults_test.go new file mode 100644 index 00000000000..2a07afa0ea2 --- /dev/null +++ b/drivers/shared/capabilities/defaults_test.go @@ -0,0 +1,23 @@ +package capabilities + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSet_NomadDefaults(t *testing.T) { + result := NomadDefaults() + require.Len(t, result.Slice(false), 13) + defaults := strings.ToLower(HCLSpecLiteral) + for _, c := range result.Slice(false) { + require.Contains(t, defaults, c) + } +} + +func TestSet_DockerDefaults(t *testing.T) { + result := DockerDefaults() + require.Len(t, result.Slice(false), 14) + require.Contains(t, result.String(), "net_raw") +} diff --git a/drivers/shared/capabilities/set.go b/drivers/shared/capabilities/set.go new file mode 100644 index 00000000000..046573e2a40 --- /dev/null +++ b/drivers/shared/capabilities/set.go @@ -0,0 +1,110 @@ +// Package capabilities is used for managing sets of linux capabilities. +package capabilities + +import ( + "sort" + "strings" +) + +type nothing struct{} + +var null = nothing{} + +// Set represents a group linux capabilities, implementing some useful set +// operations, taking care of name normalization, and sentinel value expansions. +// +// Linux capabilities can be expressed in multiple ways when working with docker +// and/or libcontainer, along with Nomad. +// +// Capability names may be upper or lower case, and may or may not be prefixed +// with "CAP_" or "cap_". On top of that, Nomad interprets the special name "all" +// and "ALL" to mean "all capabilities supported by the operating system". +type Set struct { + data map[string]nothing +} + +func New(caps []string) *Set { + m := make(map[string]nothing, len(caps)) + for _, c := range caps { + insert(m, c) + } + return &Set{data: m} +} + +// Add cap into s. +func (s *Set) Add(cap string) { + insert(s.data, cap) +} + +func insert(data map[string]nothing, cap string) { + switch name := normalize(cap); name { + case "": + case "all": + for k, v := range Supported().data { + data[k] = v + } + return + default: + data[name] = null + } +} + +// Remove caps from s. +func (s *Set) Remove(caps []string) { + for _, c := range caps { + name := normalize(c) + if name == "all" { + s.data = make(map[string]nothing) + return + } + delete(s.data, name) + } +} + +// Difference returns the Set of elements of b not in s. +func (s *Set) Difference(b *Set) *Set { + data := make(map[string]nothing) + for c := range b.data { + if _, exists := s.data[c]; !exists { + data[c] = null + } + } + return &Set{data: data} +} + +// Empty return true if no capabilities exist in s. +func (s *Set) Empty() bool { + return len(s.data) == 0 +} + +// String returns the normalized and sorted string representation of s. +func (s *Set) String() string { + return strings.Join(s.Slice(false), ", ") +} + +// Slice returns a sorted slice of capabilities in s. +// +// big - indicates whether to uppercase and prefix capabilities with CAP_ +func (s *Set) Slice(upper bool) []string { + caps := make([]string, 0, len(s.data)) + for c := range s.data { + if upper { + c = "CAP_" + strings.ToUpper(c) + } + caps = append(caps, c) + } + sort.Strings(caps) + return caps +} + +// linux capabilities are often named in 4 possible ways - upper or lower case, +// and with or without a CAP_ prefix +// +// since we must do comparisons on cap names, always normalize the names before +// letting them into the Set data-structure +func normalize(name string) string { + spaces := strings.TrimSpace(name) + lower := strings.ToLower(spaces) + trim := strings.TrimPrefix(lower, "cap_") + return trim +} diff --git a/drivers/shared/capabilities/set_test.go b/drivers/shared/capabilities/set_test.go new file mode 100644 index 00000000000..8e072e8b0f2 --- /dev/null +++ b/drivers/shared/capabilities/set_test.go @@ -0,0 +1,162 @@ +package capabilities + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSet_Empty(t *testing.T) { + t.Parallel() + + t.Run("nil", func(t *testing.T) { + result := New(nil).Empty() + require.True(t, result) + }) + + t.Run("empty", func(t *testing.T) { + result := New([]string{}).Empty() + require.True(t, result) + }) + + t.Run("full", func(t *testing.T) { + result := New([]string{"chown", "sys_time"}).Empty() + require.False(t, result) + }) +} + +func TestSet_New(t *testing.T) { + t.Parallel() + + t.Run("duplicates", func(t *testing.T) { + result := New([]string{"chown", "sys_time", "chown"}) + require.Equal(t, "chown, sys_time", result.String()) + }) + + t.Run("empty string", func(t *testing.T) { + result := New([]string{""}) + require.True(t, result.Empty()) + }) + + t.Run("all", func(t *testing.T) { + result := New([]string{"all"}) + exp := len(Supported().Slice(false)) + require.Len(t, result.Slice(false), exp) + }) +} + +func TestSet_Slice(t *testing.T) { + t.Parallel() + + exp := []string{"chown", "net_raw", "sys_time"} + + t.Run("lower case", func(t *testing.T) { + s := New([]string{"net_raw", "chown", "sys_time"}) + require.Equal(t, exp, s.Slice(false)) + }) + + t.Run("upper case", func(t *testing.T) { + s := New([]string{"NET_RAW", "CHOWN", "SYS_TIME"}) + require.Equal(t, exp, s.Slice(false)) + }) + + t.Run("prefix", func(t *testing.T) { + s := New([]string{"CAP_net_raw", "sys_TIME", "cap_chown"}) + require.Equal(t, exp, s.Slice(false)) + }) +} + +func TestSet_String(t *testing.T) { + t.Parallel() + + t.Run("empty", func(t *testing.T) { + result := New(nil).String() + require.Equal(t, "", result) + }) + + t.Run("full", func(t *testing.T) { + exp := "chown, net_raw, sys_time" + in := []string{"net_raw", "CAP_CHOWN", "cap_sys_time"} + result := New(in).String() + require.Equal(t, exp, result) + }) +} + +func TestSet_Add(t *testing.T) { + t.Parallel() + + t.Run("add one", func(t *testing.T) { + s := New([]string{"chown", "net_raw"}) + require.Equal(t, "chown, net_raw", s.String()) + + s.Add("CAP_SYS_TIME") + require.Equal(t, "chown, net_raw, sys_time", s.String()) + + s.Add("AF_NET") + require.Equal(t, "af_net, chown, net_raw, sys_time", s.String()) + }) + + t.Run("add empty string", func(t *testing.T) { + s := New([]string{"chown"}) + s.Add("") + require.Equal(t, "chown", s.String()) + }) + + t.Run("add all", func(t *testing.T) { + s := New([]string{"chown", "net_raw"}) + require.Equal(t, "chown, net_raw", s.String()) + + exp := len(Supported().Slice(false)) + s.Add("all") + require.Len(t, s.Slice(false), exp) + }) + +} + +func TestSet_Remove(t *testing.T) { + t.Parallel() + + t.Run("remove one", func(t *testing.T) { + s := New([]string{"af_net", "chown", "net_raw", "seteuid", "sys_time"}) + s.Remove([]string{"CAP_NET_RAW"}) + require.Equal(t, "af_net, chown, seteuid, sys_time", s.String()) + }) + + t.Run("remove couple", func(t *testing.T) { + s := New([]string{"af_net", "chown", "net_raw", "seteuid", "sys_time"}) + s.Remove([]string{"CAP_NET_RAW", "af_net"}) + require.Equal(t, "chown, seteuid, sys_time", s.String()) + }) + + t.Run("remove all", func(t *testing.T) { + s := New([]string{"af_net", "chown", "net_raw", "seteuid", "sys_time"}) + s.Remove([]string{"all"}) + require.True(t, s.Empty()) + require.Equal(t, "", s.String()) + }) +} + +func TestSet_Difference(t *testing.T) { + t.Parallel() + + t.Run("a is empty", func(t *testing.T) { + a := New(nil) + b := New([]string{"chown", "af_net"}) + result := a.Difference(b) + require.Equal(t, "af_net, chown", result.String()) + }) + + t.Run("b is empty", func(t *testing.T) { + a := New([]string{"chown", "af_net"}) + b := New(nil) + result := a.Difference(b) + require.True(t, result.Empty()) + }) + + t.Run("a diff b", func(t *testing.T) { + a := New([]string{"A", "b", "C", "d", "e", "f"}) + b := New([]string{"B", "x", "Y", "a"}) + result := a.Difference(b) + require.Equal(t, "x, y", result.String()) + }) +} diff --git a/drivers/shared/executor/executor.go b/drivers/shared/executor/executor.go index a87674d2ae5..7d738e45f63 100644 --- a/drivers/shared/executor/executor.go +++ b/drivers/shared/executor/executor.go @@ -147,6 +147,9 @@ type ExecCommand struct { // ModeIPC is the IPC isolation mode (private or host). ModeIPC string + + // Capabilities are the linux capabilities to be enabled by the task driver. + Capabilities []string } // SetWriters sets the writer for the process stdout and stderr. This should diff --git a/drivers/shared/executor/executor_linux.go b/drivers/shared/executor/executor_linux.go index 16eb27b4c0f..1bbb2839cbb 100644 --- a/drivers/shared/executor/executor_linux.go +++ b/drivers/shared/executor/executor_linux.go @@ -14,6 +14,7 @@ import ( "syscall" "time" + "github.com/hashicorp/nomad/drivers/shared/capabilities" "github.com/opencontainers/runtime-spec/specs-go" "github.com/armon/circbuf" @@ -532,28 +533,26 @@ func (l *LibcontainerExecutor) handleExecWait(ch chan *waitResult, process *libc ch <- &waitResult{ps, err} } -func configureCapabilities(cfg *lconfigs.Config, command *ExecCommand) error { - // TODO(shoenig): allow better control of these - // use capabilities list as prior to adopting libcontainer in 0.9 +func configureCapabilities(cfg *lconfigs.Config, command *ExecCommand) { - // match capabilities used in Nomad 0.8 - if command.User == "root" { - allCaps := SupportedCaps(true) + switch command.User { + case "root": + // when running as root, use the legacy set of system capabilities, so + // that we do not break existing nomad clusters using this "feature" + legacyCaps := capabilities.LegacySupported().Slice(true) cfg.Capabilities = &lconfigs.Capabilities{ - Bounding: allCaps, - Permitted: allCaps, - Effective: allCaps, + Bounding: legacyCaps, + Permitted: legacyCaps, + Effective: legacyCaps, Ambient: nil, Inheritable: nil, } - } else { - allCaps := SupportedCaps(false) + default: + // otherwise apply the plugin + task capability configuration cfg.Capabilities = &lconfigs.Capabilities{ - Bounding: allCaps, + Bounding: command.Capabilities, } } - - return nil } func configureNamespaces(pidMode, ipcMode string) lconfigs.Namespaces { @@ -759,16 +758,17 @@ func newLibcontainerConfig(command *ExecCommand) (*lconfigs.Config, error) { }, Version: "1.0.0", } + for _, device := range specconv.AllowedDevices { cfg.Cgroups.Resources.Devices = append(cfg.Cgroups.Resources.Devices, &device.Rule) } - if err := configureCapabilities(cfg, command); err != nil { - return nil, err - } + configureCapabilities(cfg, command) + if err := configureIsolation(cfg, command); err != nil { return nil, err } + if err := configureCgroups(cfg, command); err != nil { return nil, err } diff --git a/drivers/shared/executor/executor_linux_test.go b/drivers/shared/executor/executor_linux_test.go index a8bfba0a4e4..b3576797ad4 100644 --- a/drivers/shared/executor/executor_linux_test.go +++ b/drivers/shared/executor/executor_linux_test.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/taskenv" "github.com/hashicorp/nomad/client/testutil" + "github.com/hashicorp/nomad/drivers/shared/capabilities" "github.com/hashicorp/nomad/helper/testlog" "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/plugins/drivers" @@ -478,7 +479,7 @@ func TestExecutor_Capabilities(t *testing.T) { CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 -CapBnd: 0000003fffffdfff +CapBnd: 00000000a80405fb CapAmb: 0000000000000000`, }, { @@ -494,7 +495,6 @@ CapAmb: 0000000000000000`, for _, c := range cases { t.Run(c.user, func(t *testing.T) { - require := require.New(t) testExecCmd := testExecutorCommandWithChroot(t) execCmd, allocDir := testExecCmd.command, testExecCmd.allocDir @@ -504,12 +504,13 @@ CapAmb: 0000000000000000`, execCmd.ResourceLimits = true execCmd.Cmd = "/bin/bash" execCmd.Args = []string{"-c", "cat /proc/$$/status"} + execCmd.Capabilities = capabilities.NomadDefaults().Slice(true) executor := NewExecutorWithIsolation(testlog.HCLogger(t)) defer executor.Shutdown("SIGKILL", 0) _, err := executor.Launch(execCmd) - require.NoError(err) + require.NoError(t, err) ch := make(chan interface{}) go func() { @@ -521,7 +522,7 @@ CapAmb: 0000000000000000`, case <-ch: // all good case <-time.After(5 * time.Second): - require.Fail("timeout waiting for exec to shutdown") + require.Fail(t, "timeout waiting for exec to shutdown") } canonical := func(s string) string { @@ -538,7 +539,7 @@ CapAmb: 0000000000000000`, return false, fmt.Errorf("capabilities didn't match: want\n%v\n; got:\n%v\n", expected, output) } return true, nil - }, func(err error) { require.NoError(err) }) + }, func(err error) { require.NoError(t, err) }) }) } diff --git a/drivers/shared/executor/proto/executor.pb.go b/drivers/shared/executor/proto/executor.pb.go index f6defb54a30..bf6c980c290 100644 --- a/drivers/shared/executor/proto/executor.pb.go +++ b/drivers/shared/executor/proto/executor.pb.go @@ -44,6 +44,7 @@ type LaunchRequest struct { DefaultPidMode string `protobuf:"bytes,15,opt,name=default_pid_mode,json=defaultPidMode,proto3" json:"default_pid_mode,omitempty"` DefaultIpcMode string `protobuf:"bytes,16,opt,name=default_ipc_mode,json=defaultIpcMode,proto3" json:"default_ipc_mode,omitempty"` CpusetCgroup string `protobuf:"bytes,17,opt,name=cpuset_cgroup,json=cpusetCgroup,proto3" json:"cpuset_cgroup,omitempty"` + AllowCaps []string `protobuf:"bytes,18,rep,name=allow_caps,json=allowCaps,proto3" json:"allow_caps,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -193,6 +194,13 @@ func (m *LaunchRequest) GetCpusetCgroup() string { return "" } +func (m *LaunchRequest) GetAllowCaps() []string { + if m != nil { + return m.AllowCaps + } + return nil +} + type LaunchResponse struct { Process *ProcessState `protobuf:"bytes,1,opt,name=process,proto3" json:"process,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -858,71 +866,73 @@ func init() { } var fileDescriptor_66b85426380683f3 = []byte{ - // 1020 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x5b, 0x8f, 0xdb, 0x44, - 0x14, 0xae, 0x37, 0x9b, 0xdb, 0x49, 0xb2, 0x49, 0x47, 0xa8, 0xb8, 0xe1, 0xa1, 0xc1, 0x48, 0x34, - 0x82, 0xe2, 0xac, 0xb6, 0x37, 0x24, 0x24, 0x8a, 0xd8, 0x2d, 0xa8, 0xd2, 0x76, 0x15, 0x39, 0x85, - 0x4a, 0x3c, 0x60, 0x5c, 0xcf, 0x34, 0x19, 0x6d, 0xe2, 0x31, 0x33, 0xe3, 0x74, 0x91, 0x90, 0x78, - 0xe2, 0x1f, 0x80, 0xc4, 0x5f, 0xe5, 0x0d, 0xcd, 0xcd, 0x9b, 0x6c, 0x4b, 0xe5, 0x14, 0xf1, 0x14, - 0xcf, 0xc9, 0xf7, 0x9d, 0xcb, 0x9c, 0x73, 0xbe, 0x81, 0x3b, 0x98, 0xd3, 0x35, 0xe1, 0x62, 0x22, - 0x16, 0x09, 0x27, 0x78, 0x42, 0x2e, 0x48, 0x5a, 0x48, 0xc6, 0x27, 0x39, 0x67, 0x92, 0x95, 0xc7, - 0x50, 0x1f, 0xd1, 0xc7, 0x8b, 0x44, 0x2c, 0x68, 0xca, 0x78, 0x1e, 0x66, 0x6c, 0x95, 0xe0, 0x30, - 0x5f, 0x16, 0x73, 0x9a, 0x89, 0x70, 0x1b, 0x37, 0xbc, 0x35, 0x67, 0x6c, 0xbe, 0x24, 0xc6, 0xc9, - 0x8b, 0xe2, 0xe5, 0x44, 0xd2, 0x15, 0x11, 0x32, 0x59, 0xe5, 0x16, 0x10, 0x58, 0xe2, 0xc4, 0x85, - 0x37, 0xe1, 0xcc, 0xc9, 0x60, 0x82, 0xbf, 0xeb, 0xd0, 0x3b, 0x4d, 0x8a, 0x2c, 0x5d, 0x44, 0xe4, - 0xe7, 0x82, 0x08, 0x89, 0x06, 0x50, 0x4b, 0x57, 0xd8, 0xf7, 0x46, 0xde, 0xb8, 0x1d, 0xa9, 0x4f, - 0x84, 0x60, 0x3f, 0xe1, 0x73, 0xe1, 0xef, 0x8d, 0x6a, 0xe3, 0x76, 0xa4, 0xbf, 0xd1, 0x19, 0xb4, - 0x39, 0x11, 0xac, 0xe0, 0x29, 0x11, 0x7e, 0x6d, 0xe4, 0x8d, 0x3b, 0x47, 0x87, 0xe1, 0xbf, 0x25, - 0x6e, 0xe3, 0x9b, 0x90, 0x61, 0xe4, 0x78, 0xd1, 0xa5, 0x0b, 0x74, 0x0b, 0x3a, 0x42, 0x62, 0x56, - 0xc8, 0x38, 0x4f, 0xe4, 0xc2, 0xdf, 0xd7, 0xd1, 0xc1, 0x98, 0xa6, 0x89, 0x5c, 0x58, 0x00, 0xe1, - 0xdc, 0x00, 0xea, 0x25, 0x80, 0x70, 0xae, 0x01, 0x03, 0xa8, 0x91, 0x6c, 0xed, 0x37, 0x74, 0x92, - 0xea, 0x53, 0xe5, 0x5d, 0x08, 0xc2, 0xfd, 0xa6, 0xc6, 0xea, 0x6f, 0x74, 0x13, 0x5a, 0x32, 0x11, - 0xe7, 0x31, 0xa6, 0xdc, 0x6f, 0x69, 0x7b, 0x53, 0x9d, 0x4f, 0x28, 0x47, 0xb7, 0xa1, 0xef, 0xf2, - 0x89, 0x97, 0x74, 0x45, 0xa5, 0xf0, 0xdb, 0x23, 0x6f, 0xdc, 0x8a, 0x0e, 0x9c, 0xf9, 0x54, 0x5b, - 0xd1, 0x21, 0xbc, 0xf7, 0x22, 0x11, 0x34, 0x8d, 0x73, 0xce, 0x52, 0x22, 0x44, 0x9c, 0xce, 0x39, - 0x2b, 0x72, 0x1f, 0x34, 0x1a, 0xe9, 0xff, 0xa6, 0xe6, 0xaf, 0x63, 0xfd, 0x0f, 0x3a, 0x81, 0xc6, - 0x8a, 0x15, 0x99, 0x14, 0x7e, 0x67, 0x54, 0x1b, 0x77, 0x8e, 0xee, 0x54, 0xbc, 0xaa, 0xa7, 0x8a, - 0x14, 0x59, 0x2e, 0xfa, 0x16, 0x9a, 0x98, 0xac, 0xa9, 0xba, 0xf1, 0xae, 0x76, 0xf3, 0x59, 0x45, - 0x37, 0x27, 0x9a, 0x15, 0x39, 0x36, 0x5a, 0xc0, 0xf5, 0x8c, 0xc8, 0x57, 0x8c, 0x9f, 0xc7, 0x54, - 0xb0, 0x65, 0x22, 0x29, 0xcb, 0xfc, 0x9e, 0x6e, 0xe2, 0x17, 0x15, 0x5d, 0x9e, 0x19, 0xfe, 0x13, - 0x47, 0x9f, 0xe5, 0x24, 0x8d, 0x06, 0xd9, 0x15, 0x2b, 0x0a, 0xa0, 0x97, 0xb1, 0x38, 0xa7, 0x6b, - 0x26, 0x63, 0xce, 0x98, 0xf4, 0x0f, 0xf4, 0x1d, 0x75, 0x32, 0x36, 0x55, 0xb6, 0x88, 0x31, 0x89, - 0xc6, 0x30, 0xc0, 0xe4, 0x65, 0x52, 0x2c, 0x65, 0x9c, 0x53, 0x1c, 0xaf, 0x18, 0x26, 0x7e, 0x5f, - 0xb7, 0xe6, 0xc0, 0xda, 0xa7, 0x14, 0x3f, 0x65, 0x98, 0x6c, 0x22, 0x69, 0x9e, 0x1a, 0xe4, 0x60, - 0x0b, 0xf9, 0x24, 0x4f, 0x35, 0xf2, 0x23, 0xe8, 0xa5, 0x79, 0x21, 0x88, 0x74, 0xbd, 0xb9, 0xae, - 0x61, 0x5d, 0x63, 0x34, 0x5d, 0x09, 0x7e, 0x82, 0x03, 0x37, 0xfa, 0x22, 0x67, 0x99, 0x20, 0xe8, - 0x0c, 0x9a, 0xb6, 0xa7, 0x7a, 0xfe, 0x3b, 0x47, 0xf7, 0xc2, 0x6a, 0xcb, 0x18, 0xda, 0x7e, 0xcf, - 0x64, 0x22, 0x49, 0xe4, 0x9c, 0x04, 0x3d, 0xe8, 0x3c, 0x4f, 0xa8, 0xb4, 0xab, 0x15, 0xfc, 0x08, - 0x5d, 0x73, 0xfc, 0x9f, 0xc2, 0x9d, 0x42, 0x7f, 0xb6, 0x28, 0x24, 0x66, 0xaf, 0x32, 0xb7, 0xcd, - 0x37, 0xa0, 0x21, 0xe8, 0x3c, 0x4b, 0x96, 0x76, 0xa1, 0xed, 0x09, 0x7d, 0x08, 0xdd, 0x39, 0x4f, - 0x52, 0x12, 0xe7, 0x84, 0x53, 0x86, 0xfd, 0xbd, 0x91, 0x37, 0xae, 0x45, 0x1d, 0x6d, 0x9b, 0x6a, - 0x53, 0x80, 0x60, 0x70, 0xe9, 0xcd, 0x64, 0x1c, 0x2c, 0xe0, 0xc6, 0x77, 0x39, 0x56, 0x41, 0xcb, - 0x25, 0xb6, 0x81, 0xb6, 0x04, 0xc1, 0xfb, 0xcf, 0x82, 0x10, 0xdc, 0x84, 0xf7, 0x5f, 0x8b, 0x64, - 0x93, 0x18, 0xc0, 0xc1, 0xf7, 0x84, 0x0b, 0xca, 0x5c, 0x95, 0xc1, 0xa7, 0xd0, 0x2f, 0x2d, 0xf6, - 0x6e, 0x7d, 0x68, 0xae, 0x8d, 0xc9, 0x56, 0xee, 0x8e, 0xc1, 0x27, 0xd0, 0x55, 0xf7, 0x56, 0x66, - 0x3e, 0x84, 0x16, 0xcd, 0x24, 0xe1, 0x6b, 0x7b, 0x49, 0xb5, 0xa8, 0x3c, 0x07, 0xcf, 0xa1, 0x67, - 0xb1, 0xd6, 0xed, 0x37, 0x50, 0x17, 0xca, 0xb0, 0x63, 0x89, 0xcf, 0x12, 0x71, 0x6e, 0x1c, 0x19, - 0x7a, 0x70, 0x1b, 0x7a, 0x33, 0xdd, 0x89, 0x37, 0x37, 0xaa, 0xee, 0x1a, 0xa5, 0x8a, 0x75, 0x40, - 0x5b, 0xfe, 0x39, 0x74, 0x1e, 0x5f, 0x90, 0xd4, 0x11, 0x1f, 0x40, 0x0b, 0x93, 0x04, 0x2f, 0x69, - 0x46, 0x6c, 0x52, 0xc3, 0xd0, 0xbc, 0x0c, 0xa1, 0x7b, 0x19, 0xc2, 0x67, 0xee, 0x65, 0x88, 0x4a, - 0xac, 0xd3, 0xf9, 0xbd, 0xd7, 0x75, 0xbe, 0x76, 0xa9, 0xf3, 0xc1, 0x31, 0x74, 0x4d, 0x30, 0x5b, - 0xff, 0x0d, 0x68, 0xb0, 0x42, 0xe6, 0x85, 0xd4, 0xb1, 0xba, 0x91, 0x3d, 0xa1, 0x0f, 0xa0, 0x4d, - 0x2e, 0xa8, 0x8c, 0x53, 0xb5, 0x93, 0x7b, 0xba, 0x82, 0x96, 0x32, 0x1c, 0x33, 0x4c, 0x82, 0xdf, - 0x3d, 0xe8, 0x6e, 0x4e, 0xac, 0x8a, 0x9d, 0x53, 0x6c, 0x2b, 0x55, 0x9f, 0x6f, 0xe5, 0x6f, 0xdc, - 0x4d, 0x6d, 0xf3, 0x6e, 0x50, 0x08, 0xfb, 0xea, 0xcd, 0xd3, 0xaf, 0xc5, 0xdb, 0xcb, 0xd6, 0xb8, - 0xa3, 0x3f, 0xdb, 0xd0, 0x7a, 0x6c, 0x17, 0x09, 0xfd, 0x02, 0x0d, 0xb3, 0xfd, 0xe8, 0x7e, 0xd5, - 0xad, 0xdb, 0x7a, 0x28, 0x87, 0x0f, 0x76, 0xa5, 0xd9, 0xfe, 0x5d, 0x43, 0x02, 0xf6, 0x95, 0x0e, - 0xa0, 0xbb, 0x55, 0x3d, 0x6c, 0x88, 0xc8, 0xf0, 0xde, 0x6e, 0xa4, 0x32, 0xe8, 0x6f, 0xd0, 0x72, - 0xeb, 0x8c, 0x1e, 0x56, 0xf5, 0x71, 0x45, 0x4e, 0x86, 0x9f, 0xef, 0x4e, 0x2c, 0x13, 0xf8, 0xc3, - 0x83, 0xfe, 0x95, 0x95, 0x46, 0x5f, 0x56, 0xf5, 0xf7, 0x66, 0xd5, 0x19, 0x3e, 0x7a, 0x67, 0x7e, - 0x99, 0xd6, 0xaf, 0xd0, 0xb4, 0xda, 0x81, 0x2a, 0x77, 0x74, 0x5b, 0x7e, 0x86, 0x0f, 0x77, 0xe6, - 0x95, 0xd1, 0x2f, 0xa0, 0xae, 0x75, 0x01, 0x55, 0x6e, 0xeb, 0xa6, 0x76, 0x0d, 0xef, 0xef, 0xc8, - 0x72, 0x71, 0x0f, 0x3d, 0x35, 0xff, 0x46, 0x58, 0xaa, 0xcf, 0xff, 0x96, 0x62, 0x55, 0x9f, 0xff, - 0x2b, 0xfa, 0xa5, 0xe7, 0x5f, 0xad, 0x61, 0xf5, 0xf9, 0xdf, 0xd0, 0xbb, 0xea, 0xf3, 0xbf, 0xa9, - 0x5b, 0xc1, 0x35, 0xf4, 0x97, 0x07, 0x3d, 0x65, 0x9a, 0x49, 0x4e, 0x92, 0x15, 0xcd, 0xe6, 0xe8, - 0x51, 0x45, 0xf1, 0x56, 0x2c, 0x23, 0xe0, 0x96, 0xe9, 0x52, 0xf9, 0xea, 0xdd, 0x1d, 0xb8, 0xb4, - 0xc6, 0xde, 0xa1, 0xf7, 0x75, 0xf3, 0x87, 0xba, 0xd1, 0xac, 0x86, 0xfe, 0xb9, 0xfb, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x32, 0xbc, 0x95, 0x4b, 0x31, 0x0c, 0x00, 0x00, + // 1041 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xed, 0x6f, 0x1b, 0xc5, + 0x13, 0xee, 0xc5, 0x89, 0x5f, 0xc6, 0x76, 0xe2, 0xae, 0x7e, 0xca, 0xef, 0x6a, 0x84, 0x6a, 0x0e, + 0x89, 0x5a, 0x50, 0x2e, 0x51, 0xfa, 0x86, 0x84, 0x44, 0x11, 0x49, 0x41, 0x95, 0xd2, 0x28, 0xba, + 0x14, 0x2a, 0xf1, 0x81, 0x63, 0x7b, 0xb7, 0xb5, 0x57, 0xb1, 0x6f, 0x97, 0xdd, 0x3d, 0x27, 0x48, + 0x48, 0x7c, 0xe2, 0x3f, 0x00, 0xa9, 0x7f, 0x2e, 0xda, 0xb7, 0x8b, 0x9d, 0x96, 0xea, 0x5c, 0xc4, + 0x27, 0xdf, 0x8e, 0x9f, 0x67, 0x66, 0x76, 0x67, 0xe6, 0x19, 0xb8, 0x9b, 0x0b, 0xba, 0x20, 0x42, + 0xee, 0xc9, 0x29, 0x16, 0x24, 0xdf, 0x23, 0x97, 0x24, 0x2b, 0x15, 0x13, 0x7b, 0x5c, 0x30, 0xc5, + 0xaa, 0x63, 0x6c, 0x8e, 0xe8, 0x93, 0x29, 0x96, 0x53, 0x9a, 0x31, 0xc1, 0xe3, 0x82, 0xcd, 0x71, + 0x1e, 0xf3, 0x59, 0x39, 0xa1, 0x85, 0x8c, 0x57, 0x71, 0xc3, 0xdb, 0x13, 0xc6, 0x26, 0x33, 0x62, + 0x9d, 0xbc, 0x2c, 0x5f, 0xed, 0x29, 0x3a, 0x27, 0x52, 0xe1, 0x39, 0x77, 0x80, 0xc8, 0x11, 0xf7, + 0x7c, 0x78, 0x1b, 0xce, 0x9e, 0x2c, 0x26, 0x7a, 0xdd, 0x84, 0xfe, 0x31, 0x2e, 0x8b, 0x6c, 0x9a, + 0x90, 0x5f, 0x4a, 0x22, 0x15, 0x1a, 0x40, 0x23, 0x9b, 0xe7, 0x61, 0x30, 0x0a, 0xc6, 0x9d, 0x44, + 0x7f, 0x22, 0x04, 0x9b, 0x58, 0x4c, 0x64, 0xb8, 0x31, 0x6a, 0x8c, 0x3b, 0x89, 0xf9, 0x46, 0x27, + 0xd0, 0x11, 0x44, 0xb2, 0x52, 0x64, 0x44, 0x86, 0x8d, 0x51, 0x30, 0xee, 0x1e, 0xec, 0xc7, 0xff, + 0x94, 0xb8, 0x8b, 0x6f, 0x43, 0xc6, 0x89, 0xe7, 0x25, 0x57, 0x2e, 0xd0, 0x6d, 0xe8, 0x4a, 0x95, + 0xb3, 0x52, 0xa5, 0x1c, 0xab, 0x69, 0xb8, 0x69, 0xa2, 0x83, 0x35, 0x9d, 0x62, 0x35, 0x75, 0x00, + 0x22, 0x84, 0x05, 0x6c, 0x55, 0x00, 0x22, 0x84, 0x01, 0x0c, 0xa0, 0x41, 0x8a, 0x45, 0xd8, 0x34, + 0x49, 0xea, 0x4f, 0x9d, 0x77, 0x29, 0x89, 0x08, 0x5b, 0x06, 0x6b, 0xbe, 0xd1, 0x2d, 0x68, 0x2b, + 0x2c, 0xcf, 0xd3, 0x9c, 0x8a, 0xb0, 0x6d, 0xec, 0x2d, 0x7d, 0x3e, 0xa2, 0x02, 0xdd, 0x81, 0x1d, + 0x9f, 0x4f, 0x3a, 0xa3, 0x73, 0xaa, 0x64, 0xd8, 0x19, 0x05, 0xe3, 0x76, 0xb2, 0xed, 0xcd, 0xc7, + 0xc6, 0x8a, 0xf6, 0xe1, 0x7f, 0x2f, 0xb1, 0xa4, 0x59, 0xca, 0x05, 0xcb, 0x88, 0x94, 0x69, 0x36, + 0x11, 0xac, 0xe4, 0x21, 0x18, 0x34, 0x32, 0xff, 0x9d, 0xda, 0xbf, 0x0e, 0xcd, 0x3f, 0xe8, 0x08, + 0x9a, 0x73, 0x56, 0x16, 0x4a, 0x86, 0xdd, 0x51, 0x63, 0xdc, 0x3d, 0xb8, 0x5b, 0xf3, 0xa9, 0x9e, + 0x69, 0x52, 0xe2, 0xb8, 0xe8, 0x3b, 0x68, 0xe5, 0x64, 0x41, 0xf5, 0x8b, 0xf7, 0x8c, 0x9b, 0xcf, + 0x6b, 0xba, 0x39, 0x32, 0xac, 0xc4, 0xb3, 0xd1, 0x14, 0x6e, 0x16, 0x44, 0x5d, 0x30, 0x71, 0x9e, + 0x52, 0xc9, 0x66, 0x58, 0x51, 0x56, 0x84, 0x7d, 0x53, 0xc4, 0x2f, 0x6b, 0xba, 0x3c, 0xb1, 0xfc, + 0xa7, 0x9e, 0x7e, 0xc6, 0x49, 0x96, 0x0c, 0x8a, 0x6b, 0x56, 0x14, 0x41, 0xbf, 0x60, 0x29, 0xa7, + 0x0b, 0xa6, 0x52, 0xc1, 0x98, 0x0a, 0xb7, 0xcd, 0x1b, 0x75, 0x0b, 0x76, 0xaa, 0x6d, 0x09, 0x63, + 0x0a, 0x8d, 0x61, 0x90, 0x93, 0x57, 0xb8, 0x9c, 0xa9, 0x94, 0xd3, 0x3c, 0x9d, 0xb3, 0x9c, 0x84, + 0x3b, 0xa6, 0x34, 0xdb, 0xce, 0x7e, 0x4a, 0xf3, 0x67, 0x2c, 0x27, 0xcb, 0x48, 0xca, 0x33, 0x8b, + 0x1c, 0xac, 0x20, 0x9f, 0xf2, 0xcc, 0x20, 0x3f, 0x86, 0x7e, 0xc6, 0x4b, 0x49, 0x94, 0xaf, 0xcd, + 0x4d, 0x03, 0xeb, 0x59, 0xa3, 0xab, 0xca, 0x87, 0x00, 0x78, 0x36, 0x63, 0x17, 0x69, 0x86, 0xb9, + 0x0c, 0x91, 0x69, 0x9c, 0x8e, 0xb1, 0x1c, 0x62, 0x2e, 0xa3, 0x9f, 0x61, 0xdb, 0x4f, 0x86, 0xe4, + 0xac, 0x90, 0x04, 0x9d, 0x40, 0xcb, 0x95, 0xdc, 0x8c, 0x47, 0xf7, 0xe0, 0x7e, 0x5c, 0x6f, 0x56, + 0x63, 0xd7, 0x0e, 0x67, 0x0a, 0x2b, 0x92, 0x78, 0x27, 0x51, 0x1f, 0xba, 0x2f, 0x30, 0x55, 0x6e, + 0xf2, 0xa2, 0x9f, 0xa0, 0x67, 0x8f, 0xff, 0x51, 0xb8, 0x63, 0xd8, 0x39, 0x9b, 0x96, 0x2a, 0x67, + 0x17, 0x85, 0x1f, 0xf6, 0x5d, 0x68, 0x4a, 0x3a, 0x29, 0xf0, 0xcc, 0xcd, 0xbb, 0x3b, 0xa1, 0x8f, + 0xa0, 0x37, 0x11, 0x38, 0x23, 0x29, 0x27, 0x82, 0xb2, 0x3c, 0xdc, 0x18, 0x05, 0xe3, 0x46, 0xd2, + 0x35, 0xb6, 0x53, 0x63, 0x8a, 0x10, 0x0c, 0xae, 0xbc, 0xd9, 0x8c, 0xa3, 0x29, 0xec, 0x7e, 0xcf, + 0x73, 0x1d, 0xb4, 0x9a, 0x71, 0x17, 0x68, 0x45, 0x2f, 0x82, 0x7f, 0xad, 0x17, 0xd1, 0x2d, 0xf8, + 0xff, 0x1b, 0x91, 0x5c, 0x12, 0x03, 0xd8, 0xfe, 0x81, 0x08, 0x49, 0x99, 0xbf, 0x65, 0xf4, 0x19, + 0xec, 0x54, 0x16, 0xf7, 0xb6, 0x21, 0xb4, 0x16, 0xd6, 0xe4, 0x6e, 0xee, 0x8f, 0xd1, 0xa7, 0xd0, + 0xd3, 0xef, 0x56, 0x65, 0x3e, 0x84, 0x36, 0x2d, 0x14, 0x11, 0x0b, 0xf7, 0x48, 0x8d, 0xa4, 0x3a, + 0x47, 0x2f, 0xa0, 0xef, 0xb0, 0xce, 0xed, 0xb7, 0xb0, 0x25, 0xb5, 0x61, 0xcd, 0x2b, 0x3e, 0xc7, + 0xf2, 0xdc, 0x3a, 0xb2, 0xf4, 0xe8, 0x0e, 0xf4, 0xcf, 0x4c, 0x25, 0xde, 0x5e, 0xa8, 0x2d, 0x5f, + 0x28, 0x7d, 0x59, 0x0f, 0x74, 0xd7, 0x3f, 0x87, 0xee, 0x93, 0x4b, 0x92, 0x79, 0xe2, 0x43, 0x68, + 0xe7, 0x04, 0xe7, 0x33, 0x5a, 0x10, 0x97, 0xd4, 0x30, 0xb6, 0x8b, 0x23, 0xf6, 0x8b, 0x23, 0x7e, + 0xee, 0x17, 0x47, 0x52, 0x61, 0xfd, 0x1a, 0xd8, 0x78, 0x73, 0x0d, 0x34, 0xae, 0xd6, 0x40, 0x74, + 0x08, 0x3d, 0x1b, 0xcc, 0xdd, 0x7f, 0x17, 0x9a, 0xac, 0x54, 0xbc, 0x54, 0x26, 0x56, 0x2f, 0x71, + 0x27, 0xf4, 0x01, 0x74, 0xc8, 0x25, 0x55, 0x69, 0xa6, 0x47, 0x76, 0xc3, 0xdc, 0xa0, 0xad, 0x0d, + 0x87, 0x2c, 0x27, 0xd1, 0x1f, 0x01, 0xf4, 0x96, 0x3b, 0x56, 0xc7, 0xe6, 0x34, 0x77, 0x37, 0xd5, + 0x9f, 0xef, 0xe4, 0x2f, 0xbd, 0x4d, 0x63, 0xf9, 0x6d, 0x50, 0x0c, 0x9b, 0x7a, 0x25, 0x9a, 0x65, + 0xf2, 0xee, 0x6b, 0x1b, 0xdc, 0xc1, 0x5f, 0x1d, 0x68, 0x3f, 0x71, 0x83, 0x84, 0x7e, 0x85, 0xa6, + 0x9d, 0x7e, 0xf4, 0xa0, 0xee, 0xd4, 0xad, 0xec, 0xd1, 0xe1, 0xc3, 0x75, 0x69, 0xae, 0x7e, 0x37, + 0x90, 0x84, 0x4d, 0xad, 0x03, 0xe8, 0x5e, 0x5d, 0x0f, 0x4b, 0x22, 0x32, 0xbc, 0xbf, 0x1e, 0xa9, + 0x0a, 0xfa, 0x3b, 0xb4, 0xfd, 0x38, 0xa3, 0x47, 0x75, 0x7d, 0x5c, 0x93, 0x93, 0xe1, 0x17, 0xeb, + 0x13, 0xab, 0x04, 0xfe, 0x0c, 0x60, 0xe7, 0xda, 0x48, 0xa3, 0xaf, 0xea, 0xfa, 0x7b, 0xbb, 0xea, + 0x0c, 0x1f, 0xbf, 0x37, 0xbf, 0x4a, 0xeb, 0x37, 0x68, 0x39, 0xed, 0x40, 0xb5, 0x2b, 0xba, 0x2a, + 0x3f, 0xc3, 0x47, 0x6b, 0xf3, 0xaa, 0xe8, 0x97, 0xb0, 0x65, 0x74, 0x01, 0xd5, 0x2e, 0xeb, 0xb2, + 0x76, 0x0d, 0x1f, 0xac, 0xc9, 0xf2, 0x71, 0xf7, 0x03, 0xdd, 0xff, 0x56, 0x58, 0xea, 0xf7, 0xff, + 0x8a, 0x62, 0xd5, 0xef, 0xff, 0x6b, 0xfa, 0x65, 0xfa, 0x5f, 0x8f, 0x61, 0xfd, 0xfe, 0x5f, 0xd2, + 0xbb, 0xfa, 0xfd, 0xbf, 0xac, 0x5b, 0xd1, 0x0d, 0xf4, 0x3a, 0x80, 0xbe, 0x36, 0x9d, 0x29, 0x41, + 0xf0, 0x9c, 0x16, 0x13, 0xf4, 0xb8, 0xa6, 0x78, 0x6b, 0x96, 0x15, 0x70, 0xc7, 0xf4, 0xa9, 0x7c, + 0xfd, 0xfe, 0x0e, 0x7c, 0x5a, 0xe3, 0x60, 0x3f, 0xf8, 0xa6, 0xf5, 0xe3, 0x96, 0xd5, 0xac, 0xa6, + 0xf9, 0xb9, 0xf7, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x41, 0x13, 0xe3, 0x8e, 0x50, 0x0c, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/drivers/shared/executor/proto/executor.proto b/drivers/shared/executor/proto/executor.proto index db0a7b3cbfd..9ac241209fc 100644 --- a/drivers/shared/executor/proto/executor.proto +++ b/drivers/shared/executor/proto/executor.proto @@ -45,6 +45,7 @@ message LaunchRequest { string default_pid_mode = 15; string default_ipc_mode = 16; string cpuset_cgroup = 17; + repeated string allow_caps = 18; } message LaunchResponse {