update vendor
Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
This commit is contained in:
parent
7a437ada25
commit
639756e8c6
4300 changed files with 824810 additions and 9292 deletions
|
@ -1,5 +1,3 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package configs
|
||||
|
||||
type FreezerState string
|
||||
|
@ -22,7 +20,7 @@ type Cgroup struct {
|
|||
// The path is assumed to be relative to the host system cgroup mountpoint.
|
||||
Path string `json:"path"`
|
||||
|
||||
// ScopePrefix decribes prefix for the scope name
|
||||
// ScopePrefix describes prefix for the scope name
|
||||
ScopePrefix string `json:"scope_prefix"`
|
||||
|
||||
// Paths represent the absolute cgroups paths to join.
|
||||
|
@ -36,7 +34,7 @@ type Cgroup struct {
|
|||
type Resources struct {
|
||||
// If this is true allow access to any kind of device within the container. If false, allow access only to devices explicitly listed in the allowed_devices list.
|
||||
// Deprecated
|
||||
AllowAllDevices bool `json:"allow_all_devices,omitempty"`
|
||||
AllowAllDevices *bool `json:"allow_all_devices,omitempty"`
|
||||
// Deprecated
|
||||
AllowedDevices []*Device `json:"allowed_devices,omitempty"`
|
||||
// Deprecated
|
||||
|
@ -60,19 +58,19 @@ type Resources struct {
|
|||
KernelMemoryTCP int64 `json:"kernel_memory_tcp"`
|
||||
|
||||
// CPU shares (relative weight vs. other containers)
|
||||
CpuShares int64 `json:"cpu_shares"`
|
||||
CpuShares uint64 `json:"cpu_shares"`
|
||||
|
||||
// CPU hardcap limit (in usecs). Allowed cpu time in a given period.
|
||||
CpuQuota int64 `json:"cpu_quota"`
|
||||
|
||||
// CPU period to be used for hardcapping (in usecs). 0 to use system default.
|
||||
CpuPeriod int64 `json:"cpu_period"`
|
||||
CpuPeriod uint64 `json:"cpu_period"`
|
||||
|
||||
// How many time CPU will use in realtime scheduling (in usecs).
|
||||
CpuRtRuntime int64 `json:"cpu_quota"`
|
||||
CpuRtRuntime int64 `json:"cpu_rt_quota"`
|
||||
|
||||
// CPU period to be used for realtime scheduling (in usecs).
|
||||
CpuRtPeriod int64 `json:"cpu_period"`
|
||||
CpuRtPeriod uint64 `json:"cpu_rt_period"`
|
||||
|
||||
// CPU to use
|
||||
CpusetCpus string `json:"cpuset_cpus"`
|
||||
|
@ -95,7 +93,7 @@ type Resources struct {
|
|||
// IO read rate limit per cgroup per device, bytes per second.
|
||||
BlkioThrottleReadBpsDevice []*ThrottleDevice `json:"blkio_throttle_read_bps_device"`
|
||||
|
||||
// IO write rate limit per cgroup per divice, bytes per second.
|
||||
// IO write rate limit per cgroup per device, bytes per second.
|
||||
BlkioThrottleWriteBpsDevice []*ThrottleDevice `json:"blkio_throttle_write_bps_device"`
|
||||
|
||||
// IO read rate limit per cgroup per device, IO per second.
|
||||
|
@ -114,11 +112,11 @@ type Resources struct {
|
|||
OomKillDisable bool `json:"oom_kill_disable"`
|
||||
|
||||
// Tuning swappiness behaviour per cgroup
|
||||
MemorySwappiness *int64 `json:"memory_swappiness"`
|
||||
MemorySwappiness *uint64 `json:"memory_swappiness"`
|
||||
|
||||
// Set priority of network traffic for container
|
||||
NetPrioIfpriomap []*IfPrioMap `json:"net_prio_ifpriomap"`
|
||||
|
||||
// Set class identifier for container's network packets
|
||||
NetClsClassid string `json:"net_cls_classid"`
|
||||
NetClsClassid uint32 `json:"net_cls_classid_u"`
|
||||
}
|
6
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go
generated
vendored
|
@ -1,6 +0,0 @@
|
|||
// +build !windows,!linux,!freebsd
|
||||
|
||||
package configs
|
||||
|
||||
type Cgroup struct {
|
||||
}
|
88
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
88
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
|
@ -7,7 +7,9 @@ import (
|
|||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Rlimit struct {
|
||||
|
@ -85,11 +87,6 @@ type Config struct {
|
|||
// that the parent process dies.
|
||||
ParentDeathSignal int `json:"parent_death_signal"`
|
||||
|
||||
// PivotDir allows a custom directory inside the container's root filesystem to be used as pivot, when NoPivotRoot is not set.
|
||||
// When a custom PivotDir not set, a temporary dir inside the root filesystem will be used. The pivot dir needs to be writeable.
|
||||
// This is required when using read only root filesystems. In these cases, a read/writeable path can be (bind) mounted somewhere inside the root filesystem to act as pivot.
|
||||
PivotDir string `json:"pivot_dir"`
|
||||
|
||||
// Path to a directory containing the container's root filesystem.
|
||||
Rootfs string `json:"rootfs"`
|
||||
|
||||
|
@ -117,8 +114,8 @@ type Config struct {
|
|||
Namespaces Namespaces `json:"namespaces"`
|
||||
|
||||
// Capabilities specify the capabilities to keep when executing the process inside the container
|
||||
// All capbilities not specified will be dropped from the processes capability mask
|
||||
Capabilities []string `json:"capabilities"`
|
||||
// All capabilities not specified will be dropped from the processes capability mask
|
||||
Capabilities *Capabilities `json:"capabilities"`
|
||||
|
||||
// Networks specifies the container's network setup to be created
|
||||
Networks []*Network `json:"networks"`
|
||||
|
@ -148,10 +145,6 @@ type Config struct {
|
|||
// More information about kernel oom score calculation here: https://lwn.net/Articles/317814/
|
||||
OomScoreAdj int `json:"oom_score_adj"`
|
||||
|
||||
// AdditionalGroups specifies the gids that should be added to supplementary groups
|
||||
// in addition to those that the user belongs to.
|
||||
AdditionalGroups []string `json:"additional_groups"`
|
||||
|
||||
// UidMappings is an array of User ID mappings for User Namespaces
|
||||
UidMappings []IDMap `json:"uid_mappings"`
|
||||
|
||||
|
@ -187,6 +180,17 @@ type Config struct {
|
|||
|
||||
// Labels are user defined metadata that is stored in the config and populated on the state
|
||||
Labels []string `json:"labels"`
|
||||
|
||||
// NoNewKeyring will not allocated a new session keyring for the container. It will use the
|
||||
// callers keyring in this case.
|
||||
NoNewKeyring bool `json:"no_new_keyring"`
|
||||
|
||||
// Rootless specifies whether the container is a rootless container.
|
||||
Rootless bool `json:"rootless"`
|
||||
|
||||
// IntelRdt specifies settings for Intel RDT/CAT group that the container is placed into
|
||||
// to limit the resources (e.g., L3 cache) the container has available
|
||||
IntelRdt *IntelRdt `json:"intel_rdt,omitempty"`
|
||||
}
|
||||
|
||||
type Hooks struct {
|
||||
|
@ -201,6 +205,19 @@ type Hooks struct {
|
|||
Poststop []Hook
|
||||
}
|
||||
|
||||
type Capabilities struct {
|
||||
// Bounding is the set of capabilities checked by the kernel.
|
||||
Bounding []string
|
||||
// Effective is the set of capabilities checked by the kernel.
|
||||
Effective []string
|
||||
// Inheritable is the capabilities preserved across execve.
|
||||
Inheritable []string
|
||||
// Permitted is the limiting superset for effective capabilities.
|
||||
Permitted []string
|
||||
// Ambient is the ambient set of capabilities that are kept.
|
||||
Ambient []string
|
||||
}
|
||||
|
||||
func (hooks *Hooks) UnmarshalJSON(b []byte) error {
|
||||
var state struct {
|
||||
Prestart []CommandHook
|
||||
|
@ -248,13 +265,7 @@ func (hooks Hooks) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
// HookState is the payload provided to a hook on execution.
|
||||
type HookState struct {
|
||||
Version string `json:"ociVersion"`
|
||||
ID string `json:"id"`
|
||||
Pid int `json:"pid"`
|
||||
Root string `json:"root"`
|
||||
BundlePath string `json:"bundlePath"`
|
||||
}
|
||||
type HookState specs.State
|
||||
|
||||
type Hook interface {
|
||||
// Run executes the hook with the provided state.
|
||||
|
@ -300,29 +311,38 @@ func (c Command) Run(s HookState) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := exec.Cmd{
|
||||
Path: c.Path,
|
||||
Args: c.Args,
|
||||
Env: c.Env,
|
||||
Stdin: bytes.NewReader(b),
|
||||
Path: c.Path,
|
||||
Args: c.Args,
|
||||
Env: c.Env,
|
||||
Stdin: bytes.NewReader(b),
|
||||
Stdout: &stdout,
|
||||
Stderr: &stderr,
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
errC := make(chan error, 1)
|
||||
go func() {
|
||||
out, err := cmd.CombinedOutput()
|
||||
err := cmd.Wait()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s: %s", err, out)
|
||||
err = fmt.Errorf("error running hook: %v, stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
|
||||
}
|
||||
errC <- err
|
||||
}()
|
||||
var timerCh <-chan time.Time
|
||||
if c.Timeout != nil {
|
||||
select {
|
||||
case err := <-errC:
|
||||
return err
|
||||
case <-time.After(*c.Timeout):
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
|
||||
}
|
||||
timer := time.NewTimer(*c.Timeout)
|
||||
defer timer.Stop()
|
||||
timerCh = timer.C
|
||||
}
|
||||
select {
|
||||
case err := <-errC:
|
||||
return err
|
||||
case <-timerCh:
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
|
||||
}
|
||||
return <-errC
|
||||
}
|
||||
|
|
61
vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go
generated
vendored
Normal file
61
vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package configs
|
||||
|
||||
import "fmt"
|
||||
|
||||
// HostUID gets the translated uid for the process on host which could be
|
||||
// different when user namespaces are enabled.
|
||||
func (c Config) HostUID(containerId int) (int, error) {
|
||||
if c.Namespaces.Contains(NEWUSER) {
|
||||
if c.UidMappings == nil {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no uid mappings found.")
|
||||
}
|
||||
id, found := c.hostIDFromMapping(containerId, c.UidMappings)
|
||||
if !found {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no user mapping found.")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
// Return unchanged id.
|
||||
return containerId, nil
|
||||
}
|
||||
|
||||
// HostRootUID gets the root uid for the process on host which could be non-zero
|
||||
// when user namespaces are enabled.
|
||||
func (c Config) HostRootUID() (int, error) {
|
||||
return c.HostUID(0)
|
||||
}
|
||||
|
||||
// HostGID gets the translated gid for the process on host which could be
|
||||
// different when user namespaces are enabled.
|
||||
func (c Config) HostGID(containerId int) (int, error) {
|
||||
if c.Namespaces.Contains(NEWUSER) {
|
||||
if c.GidMappings == nil {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no gid mappings found.")
|
||||
}
|
||||
id, found := c.hostIDFromMapping(containerId, c.GidMappings)
|
||||
if !found {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no group mapping found.")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
// Return unchanged id.
|
||||
return containerId, nil
|
||||
}
|
||||
|
||||
// HostRootGID gets the root gid for the process on host which could be non-zero
|
||||
// when user namespaces are enabled.
|
||||
func (c Config) HostRootGID() (int, error) {
|
||||
return c.HostGID(0)
|
||||
}
|
||||
|
||||
// Utility function that gets a host ID for a container ID from user namespace map
|
||||
// if that ID is present in the map.
|
||||
func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) {
|
||||
for _, m := range uMap {
|
||||
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
|
||||
hostID := m.HostID + (containerID - m.ContainerID)
|
||||
return hostID, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
130
vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux_test.go
generated
vendored
Normal file
130
vendor/github.com/opencontainers/runc/libcontainer/configs/config_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,130 @@
|
|||
package configs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func loadConfig(name string) (*Config, error) {
|
||||
f, err := os.Open(filepath.Join("../sample_configs", name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var container *Config
|
||||
if err := json.NewDecoder(f).Decode(&container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check that a config doesn't contain extra fields
|
||||
var configMap, abstractMap map[string]interface{}
|
||||
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(f).Decode(&abstractMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configData, err := json.Marshal(&container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(configData, &configMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k := range configMap {
|
||||
delete(abstractMap, k)
|
||||
}
|
||||
|
||||
if len(abstractMap) != 0 {
|
||||
return nil, fmt.Errorf("unknown fields: %s", abstractMap)
|
||||
}
|
||||
|
||||
return container, nil
|
||||
}
|
||||
|
||||
func TestRemoveNamespace(t *testing.T) {
|
||||
ns := Namespaces{
|
||||
{Type: NEWNET},
|
||||
}
|
||||
if !ns.Remove(NEWNET) {
|
||||
t.Fatal("NEWNET was not removed")
|
||||
}
|
||||
if len(ns) != 0 {
|
||||
t.Fatalf("namespaces should have 0 items but reports %d", len(ns))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostRootUIDNoUSERNS(t *testing.T) {
|
||||
config := &Config{
|
||||
Namespaces: Namespaces{},
|
||||
}
|
||||
uid, err := config.HostRootUID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if uid != 0 {
|
||||
t.Fatalf("expected uid 0 with no USERNS but received %d", uid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostRootUIDWithUSERNS(t *testing.T) {
|
||||
config := &Config{
|
||||
Namespaces: Namespaces{{Type: NEWUSER}},
|
||||
UidMappings: []IDMap{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
uid, err := config.HostRootUID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if uid != 1000 {
|
||||
t.Fatalf("expected uid 1000 with no USERNS but received %d", uid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostRootGIDNoUSERNS(t *testing.T) {
|
||||
config := &Config{
|
||||
Namespaces: Namespaces{},
|
||||
}
|
||||
uid, err := config.HostRootGID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if uid != 0 {
|
||||
t.Fatalf("expected gid 0 with no USERNS but received %d", uid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostRootGIDWithUSERNS(t *testing.T) {
|
||||
config := &Config{
|
||||
Namespaces: Namespaces{{Type: NEWUSER}},
|
||||
GidMappings: []IDMap{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
uid, err := config.HostRootGID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if uid != 1000 {
|
||||
t.Fatalf("expected gid 1000 with no USERNS but received %d", uid)
|
||||
}
|
||||
}
|
191
vendor/github.com/opencontainers/runc/libcontainer/configs/config_test.go
generated
vendored
Normal file
191
vendor/github.com/opencontainers/runc/libcontainer/configs/config_test.go
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
package configs_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
func TestUnmarshalHooks(t *testing.T) {
|
||||
timeout := time.Second
|
||||
|
||||
prestartCmd := configs.NewCommandHook(configs.Command{
|
||||
Path: "/var/vcap/hooks/prestart",
|
||||
Args: []string{"--pid=123"},
|
||||
Env: []string{"FOO=BAR"},
|
||||
Dir: "/var/vcap",
|
||||
Timeout: &timeout,
|
||||
})
|
||||
prestart, err := json.Marshal(prestartCmd.Command)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hook := configs.Hooks{}
|
||||
err = hook.UnmarshalJSON([]byte(fmt.Sprintf(`{"Prestart" :[%s]}`, prestart)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(hook.Prestart[0], prestartCmd) {
|
||||
t.Errorf("Expected prestart to equal %+v but it was %+v",
|
||||
prestartCmd, hook.Prestart[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalHooksWithInvalidData(t *testing.T) {
|
||||
hook := configs.Hooks{}
|
||||
err := hook.UnmarshalJSON([]byte(`{invalid-json}`))
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalHooks(t *testing.T) {
|
||||
timeout := time.Second
|
||||
|
||||
prestartCmd := configs.NewCommandHook(configs.Command{
|
||||
Path: "/var/vcap/hooks/prestart",
|
||||
Args: []string{"--pid=123"},
|
||||
Env: []string{"FOO=BAR"},
|
||||
Dir: "/var/vcap",
|
||||
Timeout: &timeout,
|
||||
})
|
||||
|
||||
hook := configs.Hooks{
|
||||
Prestart: []configs.Hook{prestartCmd},
|
||||
}
|
||||
hooks, err := hook.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h := `{"poststart":null,"poststop":null,"prestart":[{"path":"/var/vcap/hooks/prestart","args":["--pid=123"],"env":["FOO=BAR"],"dir":"/var/vcap","timeout":1000000000}]}`
|
||||
if string(hooks) != h {
|
||||
t.Errorf("Expected hooks %s to equal %s", string(hooks), h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalHooks(t *testing.T) {
|
||||
timeout := time.Second
|
||||
|
||||
prestart := configs.NewCommandHook(configs.Command{
|
||||
Path: "/var/vcap/hooks/prestart",
|
||||
Args: []string{"--pid=123"},
|
||||
Env: []string{"FOO=BAR"},
|
||||
Dir: "/var/vcap",
|
||||
Timeout: &timeout,
|
||||
})
|
||||
|
||||
hook := configs.Hooks{
|
||||
Prestart: []configs.Hook{prestart},
|
||||
}
|
||||
hooks, err := hook.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
umMhook := configs.Hooks{}
|
||||
err = umMhook.UnmarshalJSON(hooks)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(umMhook.Prestart[0], prestart) {
|
||||
t.Errorf("Expected hooks to be equal after mashaling -> unmarshaling them: %+v, %+v", umMhook.Prestart[0], prestart)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalHooksWithUnexpectedType(t *testing.T) {
|
||||
fHook := configs.NewFunctionHook(func(configs.HookState) error {
|
||||
return nil
|
||||
})
|
||||
hook := configs.Hooks{
|
||||
Prestart: []configs.Hook{fHook},
|
||||
}
|
||||
hooks, err := hook.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
h := `{"poststart":null,"poststop":null,"prestart":null}`
|
||||
if string(hooks) != h {
|
||||
t.Errorf("Expected hooks %s to equal %s", string(hooks), h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuncHookRun(t *testing.T) {
|
||||
state := configs.HookState{
|
||||
Version: "1",
|
||||
ID: "1",
|
||||
Pid: 1,
|
||||
Bundle: "/bundle",
|
||||
}
|
||||
|
||||
fHook := configs.NewFunctionHook(func(s configs.HookState) error {
|
||||
if !reflect.DeepEqual(state, s) {
|
||||
t.Errorf("Expected state %+v to equal %+v", state, s)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
fHook.Run(state)
|
||||
}
|
||||
|
||||
func TestCommandHookRun(t *testing.T) {
|
||||
state := configs.HookState{
|
||||
Version: "1",
|
||||
ID: "1",
|
||||
Pid: 1,
|
||||
Bundle: "/bundle",
|
||||
}
|
||||
timeout := time.Second
|
||||
|
||||
cmdHook := configs.NewCommandHook(configs.Command{
|
||||
Path: os.Args[0],
|
||||
Args: []string{os.Args[0], "-test.run=TestHelperProcess"},
|
||||
Env: []string{"FOO=BAR"},
|
||||
Dir: "/",
|
||||
Timeout: &timeout,
|
||||
})
|
||||
|
||||
err := cmdHook.Run(state)
|
||||
if err != nil {
|
||||
t.Errorf(fmt.Sprintf("Expected error to not occur but it was %+v", err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandHookRunTimeout(t *testing.T) {
|
||||
state := configs.HookState{
|
||||
Version: "1",
|
||||
ID: "1",
|
||||
Pid: 1,
|
||||
Bundle: "/bundle",
|
||||
}
|
||||
timeout := (10 * time.Millisecond)
|
||||
|
||||
cmdHook := configs.NewCommandHook(configs.Command{
|
||||
Path: os.Args[0],
|
||||
Args: []string{os.Args[0], "-test.run=TestHelperProcessWithTimeout"},
|
||||
Env: []string{"FOO=BAR"},
|
||||
Dir: "/",
|
||||
Timeout: &timeout,
|
||||
})
|
||||
|
||||
err := cmdHook.Run(state)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelperProcess(*testing.T) {
|
||||
fmt.Println("Helper Process")
|
||||
os.Exit(0)
|
||||
}
|
||||
func TestHelperProcessWithTimeout(*testing.T) {
|
||||
time.Sleep(time.Second)
|
||||
}
|
51
vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go
generated
vendored
51
vendor/github.com/opencontainers/runc/libcontainer/configs/config_unix.go
generated
vendored
|
@ -1,51 +0,0 @@
|
|||
// +build freebsd linux
|
||||
|
||||
package configs
|
||||
|
||||
import "fmt"
|
||||
|
||||
// HostUID gets the root uid for the process on host which could be non-zero
|
||||
// when user namespaces are enabled.
|
||||
func (c Config) HostUID() (int, error) {
|
||||
if c.Namespaces.Contains(NEWUSER) {
|
||||
if c.UidMappings == nil {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no user mappings found.")
|
||||
}
|
||||
id, found := c.hostIDFromMapping(0, c.UidMappings)
|
||||
if !found {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no root user mapping found.")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
// Return default root uid 0
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// HostGID gets the root gid for the process on host which could be non-zero
|
||||
// when user namespaces are enabled.
|
||||
func (c Config) HostGID() (int, error) {
|
||||
if c.Namespaces.Contains(NEWUSER) {
|
||||
if c.GidMappings == nil {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no gid mappings found.")
|
||||
}
|
||||
id, found := c.hostIDFromMapping(0, c.GidMappings)
|
||||
if !found {
|
||||
return -1, fmt.Errorf("User namespaces enabled, but no root group mapping found.")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
// Return default root gid 0
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Utility function that gets a host ID for a container ID from user namespace map
|
||||
// if that ID is present in the map.
|
||||
func (c Config) hostIDFromMapping(containerID int, uMap []IDMap) (int, bool) {
|
||||
for _, m := range uMap {
|
||||
if (containerID >= m.ContainerID) && (containerID <= (m.ContainerID + m.Size - 1)) {
|
||||
hostID := m.HostID + (containerID - m.ContainerID)
|
||||
return hostID, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
3
vendor/github.com/opencontainers/runc/libcontainer/configs/config_windows_test.go
generated
vendored
Normal file
3
vendor/github.com/opencontainers/runc/libcontainer/configs/config_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
package configs
|
||||
|
||||
// All current tests are for Unix-specific functionality
|
18
vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go
generated
vendored
18
vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build linux freebsd
|
||||
// +build linux
|
||||
|
||||
package configs
|
||||
|
||||
|
@ -107,19 +107,5 @@ var (
|
|||
Permissions: "rwm",
|
||||
},
|
||||
}, DefaultSimpleDevices...)
|
||||
DefaultAutoCreatedDevices = append([]*Device{
|
||||
{
|
||||
// /dev/fuse is created but not allowed.
|
||||
// This is to allow java to work. Because java
|
||||
// Insists on there being a /dev/fuse
|
||||
// https://github.com/docker/docker/issues/514
|
||||
// https://github.com/docker/docker/issues/2393
|
||||
//
|
||||
Path: "/dev/fuse",
|
||||
Type: 'c',
|
||||
Major: 10,
|
||||
Minor: 229,
|
||||
Permissions: "rwm",
|
||||
},
|
||||
}, DefaultSimpleDevices...)
|
||||
DefaultAutoCreatedDevices = append([]*Device{}, DefaultSimpleDevices...)
|
||||
)
|
||||
|
|
7
vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go
generated
vendored
Normal file
7
vendor/github.com/opencontainers/runc/libcontainer/configs/intelrdt.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
package configs
|
||||
|
||||
type IntelRdt struct {
|
||||
// The schema for L3 cache id and capacity bitmask (CBM)
|
||||
// Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
|
||||
L3CacheSchema string `json:"l3_cache_schema,omitempty"`
|
||||
}
|
9
vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go
generated
vendored
9
vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go
generated
vendored
|
@ -1,5 +1,11 @@
|
|||
package configs
|
||||
|
||||
const (
|
||||
// EXT_COPYUP is a directive to copy up the contents of a directory when
|
||||
// a tmpfs is mounted over it.
|
||||
EXT_COPYUP = 1 << iota
|
||||
)
|
||||
|
||||
type Mount struct {
|
||||
// Source path for the mount.
|
||||
Source string `json:"source"`
|
||||
|
@ -22,6 +28,9 @@ type Mount struct {
|
|||
// Relabel source if set, "z" indicates shared, "Z" indicates unshared.
|
||||
Relabel string `json:"relabel"`
|
||||
|
||||
// Extensions are additional flags that are specific to runc.
|
||||
Extensions int `json:"extensions"`
|
||||
|
||||
// Optional Command to be run before Source is mounted.
|
||||
PremountCmds []Command `json:"premount_cmds"`
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package configs
|
||||
|
||||
import (
|
||||
|
@ -22,8 +20,8 @@ var (
|
|||
supportedNamespaces = make(map[NamespaceType]bool)
|
||||
)
|
||||
|
||||
// nsToFile converts the namespace type to its filename
|
||||
func nsToFile(ns NamespaceType) string {
|
||||
// NsName converts the namespace type to its filename
|
||||
func NsName(ns NamespaceType) string {
|
||||
switch ns {
|
||||
case NEWNET:
|
||||
return "net"
|
||||
|
@ -50,7 +48,7 @@ func IsNamespaceSupported(ns NamespaceType) bool {
|
|||
if ok {
|
||||
return supported
|
||||
}
|
||||
nsFile := nsToFile(ns)
|
||||
nsFile := NsName(ns)
|
||||
// if the namespace type is unknown, just return false
|
||||
if nsFile == "" {
|
||||
return false
|
||||
|
@ -64,12 +62,12 @@ func IsNamespaceSupported(ns NamespaceType) bool {
|
|||
|
||||
func NamespaceTypes() []NamespaceType {
|
||||
return []NamespaceType{
|
||||
NEWUSER, // Keep user NS always first, don't move it.
|
||||
NEWIPC,
|
||||
NEWUTS,
|
||||
NEWNET,
|
||||
NEWPID,
|
||||
NEWNS,
|
||||
NEWUTS,
|
||||
NEWIPC,
|
||||
NEWUSER,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,10 +79,7 @@ type Namespace struct {
|
|||
}
|
||||
|
||||
func (n *Namespace) GetPath(pid int) string {
|
||||
if n.Path != "" {
|
||||
return n.Path
|
||||
}
|
||||
return fmt.Sprintf("/proc/%d/ns/%s", pid, nsToFile(n.Type))
|
||||
return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type))
|
||||
}
|
||||
|
||||
func (n *Namespaces) Remove(t NamespaceType) bool {
|
14
vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go
generated
vendored
14
vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_syscall.go
generated
vendored
|
@ -2,19 +2,19 @@
|
|||
|
||||
package configs
|
||||
|
||||
import "syscall"
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func (n *Namespace) Syscall() int {
|
||||
return namespaceInfo[n.Type]
|
||||
}
|
||||
|
||||
var namespaceInfo = map[NamespaceType]int{
|
||||
NEWNET: syscall.CLONE_NEWNET,
|
||||
NEWNS: syscall.CLONE_NEWNS,
|
||||
NEWUSER: syscall.CLONE_NEWUSER,
|
||||
NEWIPC: syscall.CLONE_NEWIPC,
|
||||
NEWUTS: syscall.CLONE_NEWUTS,
|
||||
NEWPID: syscall.CLONE_NEWPID,
|
||||
NEWNET: unix.CLONE_NEWNET,
|
||||
NEWNS: unix.CLONE_NEWNS,
|
||||
NEWUSER: unix.CLONE_NEWUSER,
|
||||
NEWIPC: unix.CLONE_NEWIPC,
|
||||
NEWUTS: unix.CLONE_NEWUTS,
|
||||
NEWPID: unix.CLONE_NEWPID,
|
||||
}
|
||||
|
||||
// CloneFlags parses the container's Namespaces options to set the correct
|
||||
|
|
|
@ -4,12 +4,10 @@ package configs
|
|||
|
||||
func (n *Namespace) Syscall() int {
|
||||
panic("No namespace syscall support")
|
||||
return 0
|
||||
}
|
||||
|
||||
// CloneFlags parses the container's Namespaces options to set the correct
|
||||
// flags on clone, unshare. This function returns flags only for new namespaces.
|
||||
func (n *Namespaces) CloneFlags() uintptr {
|
||||
panic("No namespace syscall support")
|
||||
return uintptr(0)
|
||||
}
|
||||
|
|
2
vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
// +build !linux,!freebsd
|
||||
// +build !linux
|
||||
|
||||
package configs
|
||||
|
||||
|
|
117
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
generated
vendored
Normal file
117
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
generated
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
package validate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
var (
|
||||
geteuid = os.Geteuid
|
||||
getegid = os.Getegid
|
||||
)
|
||||
|
||||
func (v *ConfigValidator) rootless(config *configs.Config) error {
|
||||
if err := rootlessMappings(config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rootlessMount(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// XXX: We currently can't verify the user config at all, because
|
||||
// configs.Config doesn't store the user-related configs. So this
|
||||
// has to be verified by setupUser() in init_linux.go.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasIDMapping(id int, mappings []configs.IDMap) bool {
|
||||
for _, m := range mappings {
|
||||
if id >= m.ContainerID && id < m.ContainerID+m.Size {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func rootlessMappings(config *configs.Config) error {
|
||||
if euid := geteuid(); euid != 0 {
|
||||
if !config.Namespaces.Contains(configs.NEWUSER) {
|
||||
return fmt.Errorf("rootless containers require user namespaces")
|
||||
}
|
||||
}
|
||||
|
||||
if len(config.UidMappings) == 0 {
|
||||
return fmt.Errorf("rootless containers requires at least one UID mapping")
|
||||
}
|
||||
if len(config.GidMappings) == 0 {
|
||||
return fmt.Errorf("rootless containers requires at least one UID mapping")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cgroup verifies that the user isn't trying to set any cgroup limits or paths.
|
||||
func rootlessCgroup(config *configs.Config) error {
|
||||
// Nothing set at all.
|
||||
if config.Cgroups == nil || config.Cgroups.Resources == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Used for comparing to the zero value.
|
||||
left := reflect.ValueOf(*config.Cgroups.Resources)
|
||||
right := reflect.Zero(left.Type())
|
||||
|
||||
// This is all we need to do, since specconv won't add cgroup options in
|
||||
// rootless mode.
|
||||
if !reflect.DeepEqual(left.Interface(), right.Interface()) {
|
||||
return fmt.Errorf("cannot specify resource limits in rootless container")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mount verifies that the user isn't trying to set up any mounts they don't have
|
||||
// the rights to do. In addition, it makes sure that no mount has a `uid=` or
|
||||
// `gid=` option that doesn't resolve to root.
|
||||
func rootlessMount(config *configs.Config) error {
|
||||
// XXX: We could whitelist allowed devices at this point, but I'm not
|
||||
// convinced that's a good idea. The kernel is the best arbiter of
|
||||
// access control.
|
||||
|
||||
for _, mount := range config.Mounts {
|
||||
// Check that the options list doesn't contain any uid= or gid= entries
|
||||
// that don't resolve to root.
|
||||
for _, opt := range strings.Split(mount.Data, ",") {
|
||||
if strings.HasPrefix(opt, "uid=") {
|
||||
var uid int
|
||||
n, err := fmt.Sscanf(opt, "uid=%d", &uid)
|
||||
if n != 1 || err != nil {
|
||||
// Ignore unknown mount options.
|
||||
continue
|
||||
}
|
||||
if !hasIDMapping(uid, config.UidMappings) {
|
||||
return fmt.Errorf("cannot specify uid= mount options for unmapped uid in rootless containers")
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(opt, "gid=") {
|
||||
var gid int
|
||||
n, err := fmt.Sscanf(opt, "gid=%d", &gid)
|
||||
if n != 1 || err != nil {
|
||||
// Ignore unknown mount options.
|
||||
continue
|
||||
}
|
||||
if !hasIDMapping(gid, config.GidMappings) {
|
||||
return fmt.Errorf("cannot specify gid= mount options for unmapped gid in rootless containers")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
159
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless_test.go
generated
vendored
Normal file
159
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless_test.go
generated
vendored
Normal file
|
@ -0,0 +1,159 @@
|
|||
package validate
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
func init() {
|
||||
geteuid = func() int { return 1337 }
|
||||
getegid = func() int { return 7331 }
|
||||
}
|
||||
|
||||
func rootlessConfig() *configs.Config {
|
||||
return &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Rootless: true,
|
||||
Namespaces: configs.Namespaces(
|
||||
[]configs.Namespace{
|
||||
{Type: configs.NEWUSER},
|
||||
},
|
||||
),
|
||||
UidMappings: []configs.IDMap{
|
||||
{
|
||||
HostID: geteuid(),
|
||||
ContainerID: 0,
|
||||
Size: 1,
|
||||
},
|
||||
},
|
||||
GidMappings: []configs.IDMap{
|
||||
{
|
||||
HostID: getegid(),
|
||||
ContainerID: 0,
|
||||
Size: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRootless(t *testing.T) {
|
||||
validator := New()
|
||||
|
||||
config := rootlessConfig()
|
||||
if err := validator.Validate(config); err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
/* rootlessMappings() */
|
||||
|
||||
func TestValidateRootlessUserns(t *testing.T) {
|
||||
validator := New()
|
||||
|
||||
config := rootlessConfig()
|
||||
config.Namespaces = nil
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Errorf("Expected error to occur if user namespaces not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRootlessMappingUid(t *testing.T) {
|
||||
validator := New()
|
||||
|
||||
config := rootlessConfig()
|
||||
config.UidMappings = nil
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Errorf("Expected error to occur if no uid mappings provided")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRootlessMappingGid(t *testing.T) {
|
||||
validator := New()
|
||||
|
||||
config := rootlessConfig()
|
||||
config.GidMappings = nil
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Errorf("Expected error to occur if no gid mappings provided")
|
||||
}
|
||||
}
|
||||
|
||||
/* rootlessMount() */
|
||||
|
||||
func TestValidateRootlessMountUid(t *testing.T) {
|
||||
config := rootlessConfig()
|
||||
validator := New()
|
||||
|
||||
config.Mounts = []*configs.Mount{
|
||||
{
|
||||
Source: "devpts",
|
||||
Destination: "/dev/pts",
|
||||
Device: "devpts",
|
||||
},
|
||||
}
|
||||
|
||||
if err := validator.Validate(config); err != nil {
|
||||
t.Errorf("Expected error to not occur when uid= not set in mount options: %+v", err)
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "uid=5"
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Errorf("Expected error to occur when setting uid=5 in mount options")
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "uid=0"
|
||||
if err := validator.Validate(config); err != nil {
|
||||
t.Errorf("Expected error to not occur when setting uid=0 in mount options: %+v", err)
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "uid=2"
|
||||
config.UidMappings[0].Size = 10
|
||||
if err := validator.Validate(config); err != nil {
|
||||
t.Errorf("Expected error to not occur when setting uid=2 in mount options and UidMapping[0].size is 10")
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "uid=20"
|
||||
config.UidMappings[0].Size = 10
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Errorf("Expected error to occur when setting uid=20 in mount options and UidMapping[0].size is 10")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRootlessMountGid(t *testing.T) {
|
||||
config := rootlessConfig()
|
||||
validator := New()
|
||||
|
||||
config.Mounts = []*configs.Mount{
|
||||
{
|
||||
Source: "devpts",
|
||||
Destination: "/dev/pts",
|
||||
Device: "devpts",
|
||||
},
|
||||
}
|
||||
|
||||
if err := validator.Validate(config); err != nil {
|
||||
t.Errorf("Expected error to not occur when gid= not set in mount options: %+v", err)
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "gid=5"
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Errorf("Expected error to occur when setting gid=5 in mount options")
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "gid=0"
|
||||
if err := validator.Validate(config); err != nil {
|
||||
t.Errorf("Expected error to not occur when setting gid=0 in mount options: %+v", err)
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "gid=5"
|
||||
config.GidMappings[0].Size = 10
|
||||
if err := validator.Validate(config); err != nil {
|
||||
t.Errorf("Expected error to not occur when setting gid=5 in mount options and GidMapping[0].size is 10")
|
||||
}
|
||||
|
||||
config.Mounts[0].Data = "gid=11"
|
||||
config.GidMappings[0].Size = 10
|
||||
if err := validator.Validate(config); err == nil {
|
||||
t.Errorf("Expected error to occur when setting gid=11 in mount options and GidMapping[0].size is 10")
|
||||
}
|
||||
}
|
79
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
79
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
|
@ -7,6 +7,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||
)
|
||||
|
||||
type Validator interface {
|
||||
|
@ -39,12 +41,26 @@ func (v *ConfigValidator) Validate(config *configs.Config) error {
|
|||
if err := v.sysctl(config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := v.intelrdt(config); err != nil {
|
||||
return err
|
||||
}
|
||||
if config.Rootless {
|
||||
if err := v.rootless(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rootfs validates if the rootfs is an absolute path and is not a symlink
|
||||
// to the container's root filesystem.
|
||||
func (v *ConfigValidator) rootfs(config *configs.Config) error {
|
||||
if _, err := os.Stat(config.Rootfs); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("rootfs (%s) does not exist", config.Rootfs)
|
||||
}
|
||||
return err
|
||||
}
|
||||
cleaned, err := filepath.Abs(config.Rootfs)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -80,6 +96,10 @@ func (v *ConfigValidator) security(config *configs.Config) error {
|
|||
!config.Namespaces.Contains(configs.NEWNS) {
|
||||
return fmt.Errorf("unable to restrict sys entries without a private MNT namespace")
|
||||
}
|
||||
if config.ProcessLabel != "" && !selinux.GetEnabled() {
|
||||
return fmt.Errorf("selinux label is specified in config, but selinux is disabled or not supported")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -121,6 +141,11 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error {
|
|||
}
|
||||
if strings.HasPrefix(s, "net.") {
|
||||
if config.Namespaces.Contains(configs.NEWNET) {
|
||||
if path := config.Namespaces.PathOf(configs.NEWNET); path != "" {
|
||||
if err := checkHostNs(s, path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", s)
|
||||
|
@ -131,3 +156,57 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) intelrdt(config *configs.Config) error {
|
||||
if config.IntelRdt != nil {
|
||||
if !intelrdt.IsEnabled() {
|
||||
return fmt.Errorf("intelRdt is specified in config, but Intel RDT feature is not supported or enabled")
|
||||
}
|
||||
if config.IntelRdt.L3CacheSchema == "" {
|
||||
return fmt.Errorf("intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isSymbolicLink(path string) (bool, error) {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return fi.Mode()&os.ModeSymlink == os.ModeSymlink, nil
|
||||
}
|
||||
|
||||
// checkHostNs checks whether network sysctl is used in host namespace.
|
||||
func checkHostNs(sysctlConfig string, path string) error {
|
||||
var currentProcessNetns = "/proc/self/ns/net"
|
||||
// readlink on the current processes network namespace
|
||||
destOfCurrentProcess, err := os.Readlink(currentProcessNetns)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read soft link %q error", currentProcessNetns)
|
||||
}
|
||||
|
||||
// First check if the provided path is a symbolic link
|
||||
symLink, err := isSymbolicLink(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not check that %q is a symlink: %v", path, err)
|
||||
}
|
||||
|
||||
if symLink == false {
|
||||
// The provided namespace is not a symbolic link,
|
||||
// it is not the host namespace.
|
||||
return nil
|
||||
}
|
||||
|
||||
// readlink on the path provided in the struct
|
||||
destOfContainer, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read soft link %q error", path)
|
||||
}
|
||||
if destOfContainer == destOfCurrentProcess {
|
||||
return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", sysctlConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
267
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator_test.go
generated
vendored
Normal file
267
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,267 @@
|
|||
package validate_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs/validate"
|
||||
)
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateWithInvalidRootfs(t *testing.T) {
|
||||
dir := "rootfs"
|
||||
os.Symlink("/var", dir)
|
||||
defer os.Remove(dir)
|
||||
|
||||
config := &configs.Config{
|
||||
Rootfs: dir,
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateNetworkWithoutNETNamespace(t *testing.T) {
|
||||
network := &configs.Network{Type: "loopback"}
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Namespaces: []configs.Namespace{},
|
||||
Networks: []*configs.Network{network},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateNetworkRoutesWithoutNETNamespace(t *testing.T) {
|
||||
route := &configs.Route{Gateway: "255.255.255.0"}
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Namespaces: []configs.Namespace{},
|
||||
Routes: []*configs.Route{route},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateHostname(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Hostname: "runc",
|
||||
Namespaces: configs.Namespaces(
|
||||
[]configs.Namespace{
|
||||
{Type: configs.NEWUTS},
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateHostnameWithoutUTSNamespace(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Hostname: "runc",
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSecurityWithMaskPaths(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
MaskPaths: []string{"/proc/kcore"},
|
||||
Namespaces: configs.Namespaces(
|
||||
[]configs.Namespace{
|
||||
{Type: configs.NEWNS},
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSecurityWithROPaths(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
ReadonlyPaths: []string{"/proc/sys"},
|
||||
Namespaces: configs.Namespaces(
|
||||
[]configs.Namespace{
|
||||
{Type: configs.NEWNS},
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur: %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSecurityWithoutNEWNS(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
MaskPaths: []string{"/proc/kcore"},
|
||||
ReadonlyPaths: []string{"/proc/sys"},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateUsernamespace(t *testing.T) {
|
||||
if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
|
||||
t.Skip("userns is unsupported")
|
||||
}
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Namespaces: configs.Namespaces(
|
||||
[]configs.Namespace{
|
||||
{Type: configs.NEWUSER},
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("expected error to not occur %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateUsernamespaceWithoutUserNS(t *testing.T) {
|
||||
uidMap := configs.IDMap{ContainerID: 123}
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
UidMappings: []configs.IDMap{uidMap},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSysctl(t *testing.T) {
|
||||
sysctl := map[string]string{
|
||||
"fs.mqueue.ctl": "ctl",
|
||||
"net.ctl": "ctl",
|
||||
"kernel.ctl": "ctl",
|
||||
}
|
||||
|
||||
for k, v := range sysctl {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Sysctl: map[string]string{k: v},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateValidSysctl(t *testing.T) {
|
||||
sysctl := map[string]string{
|
||||
"fs.mqueue.ctl": "ctl",
|
||||
"net.ctl": "ctl",
|
||||
"kernel.msgmax": "ctl",
|
||||
}
|
||||
|
||||
for k, v := range sysctl {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Sysctl: map[string]string{k: v},
|
||||
Namespaces: []configs.Namespace{
|
||||
{
|
||||
Type: configs.NEWNET,
|
||||
},
|
||||
{
|
||||
Type: configs.NEWIPC,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err != nil {
|
||||
t.Errorf("Expected error to not occur with {%s=%s} but got: %q", k, v, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSysctlWithSameNs(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Sysctl: map[string]string{"net.ctl": "ctl"},
|
||||
Namespaces: configs.Namespaces(
|
||||
[]configs.Namespace{
|
||||
{
|
||||
Type: configs.NEWNET,
|
||||
Path: "/proc/self/ns/net",
|
||||
},
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSysctlWithoutNETNamespace(t *testing.T) {
|
||||
config := &configs.Config{
|
||||
Rootfs: "/var",
|
||||
Sysctl: map[string]string{"net.ctl": "ctl"},
|
||||
Namespaces: []configs.Namespace{},
|
||||
}
|
||||
|
||||
validator := validate.New()
|
||||
err := validator.Validate(config)
|
||||
if err == nil {
|
||||
t.Error("Expected error to occur but it was nil")
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue