From d081e5d70cc8ed0938acf4418511da29f9deb6fe Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 9 Aug 2021 11:11:54 +0200 Subject: [PATCH] runconfig: decodeContainerConfig() return early if there's no HostConfig Each of the validation functions depended on HostConfig being not `nil`. Use an early return, instead of continuing, and checking if it's `nil` in each of the validate functions. Signed-off-by: Sebastiaan van Stijn --- runconfig/config.go | 36 +++++++++------------------------ runconfig/config_unix.go | 2 +- runconfig/hostconfig.go | 18 ++++------------- runconfig/hostconfig_unix.go | 30 +++------------------------ runconfig/hostconfig_windows.go | 31 ++++------------------------ 5 files changed, 22 insertions(+), 95 deletions(-) diff --git a/runconfig/config.go b/runconfig/config.go index 41f953ac14..1b71b2042f 100644 --- a/runconfig/config.go +++ b/runconfig/config.go @@ -33,58 +33,42 @@ func (r ContainerDecoder) DecodeHostConfig(src io.Reader) (*container.HostConfig } // decodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper -// struct and returns both a Config and a HostConfig struct +// struct and returns both a Config and a HostConfig struct, and performs some +// validation. Certain parameters need daemon-side validation that cannot be done +// on the client, as only the daemon knows what is valid for the platform. // Be aware this function is not checking whether the resulted structs are nil, // it's your business to do so func decodeContainerConfig(src io.Reader, si *sysinfo.SysInfo) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { var w ContainerConfigWrapper - - decoder := json.NewDecoder(src) - if err := decoder.Decode(&w); err != nil { + if err := json.NewDecoder(src).Decode(&w); err != nil { return nil, nil, nil, err } hc := w.getHostConfig() - - // Perform platform-specific processing of Volumes and Binds. - if w.Config != nil && hc != nil { - - // Initialize the volumes map if currently nil - if w.Config.Volumes == nil { - w.Config.Volumes = make(map[string]struct{}) - } + if hc == nil { + // We may not be passed a host config, such as in the case of docker commit + return w.Config, hc, w.NetworkingConfig, nil } - - // Certain parameters need daemon-side validation that cannot be done - // on the client, as only the daemon knows what is valid for the platform. if err := validateNetMode(w.Config, hc); err != nil { return nil, nil, nil, err } - - // Validate isolation if err := validateIsolation(hc); err != nil { return nil, nil, nil, err } - - // Validate QoS if err := validateQoS(hc); err != nil { return nil, nil, nil, err } - - // Validate Resources if err := validateResources(hc, si); err != nil { return nil, nil, nil, err } - - // Validate Privileged if err := validatePrivileged(hc); err != nil { return nil, nil, nil, err } - - // Validate ReadonlyRootfs if err := validateReadonlyRootfs(hc); err != nil { return nil, nil, nil, err } - + if w.Config != nil && w.Config.Volumes == nil { + w.Config.Volumes = make(map[string]struct{}) + } return w.Config, hc, w.NetworkingConfig, nil } diff --git a/runconfig/config_unix.go b/runconfig/config_unix.go index 65e8d6fcd4..fb0d96d524 100644 --- a/runconfig/config_unix.go +++ b/runconfig/config_unix.go @@ -24,7 +24,7 @@ func (w *ContainerConfigWrapper) getHostConfig() *container.HostConfig { if hc == nil && w.InnerHostConfig != nil { hc = w.InnerHostConfig - } else if w.InnerHostConfig != nil { + } else if hc != nil && w.InnerHostConfig != nil { if hc.Memory != 0 && w.InnerHostConfig.Memory == 0 { w.InnerHostConfig.Memory = hc.Memory } diff --git a/runconfig/hostconfig.go b/runconfig/hostconfig.go index 7d99e5acfa..1d6266d5f7 100644 --- a/runconfig/hostconfig.go +++ b/runconfig/hostconfig.go @@ -11,15 +11,11 @@ import ( // DecodeHostConfig creates a HostConfig based on the specified Reader. // It assumes the content of the reader will be JSON, and decodes it. func decodeHostConfig(src io.Reader) (*container.HostConfig, error) { - decoder := json.NewDecoder(src) - var w ContainerConfigWrapper - if err := decoder.Decode(&w); err != nil { + if err := json.NewDecoder(src).Decode(&w); err != nil { return nil, err } - - hc := w.getHostConfig() - return hc, nil + return w.getHostConfig(), nil } // SetDefaultNetModeIfBlank changes the NetworkMode in a HostConfig structure @@ -27,20 +23,14 @@ func decodeHostConfig(src io.Reader) (*container.HostConfig, error) { // the validation of the network mode was moved from the docker CLI to the // docker daemon. func SetDefaultNetModeIfBlank(hc *container.HostConfig) { - if hc != nil { - if hc.NetworkMode == container.NetworkMode("") { - hc.NetworkMode = container.NetworkMode("default") - } + if hc != nil && hc.NetworkMode == "" { + hc.NetworkMode = "default" } } // validateNetContainerMode ensures that the various combinations of requested // network settings wrt container mode are valid. func validateNetContainerMode(c *container.Config, hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } parts := strings.Split(string(hc.NetworkMode), ":") if parts[0] == "container" { if len(parts) < 2 || parts[1] == "" { diff --git a/runconfig/hostconfig_unix.go b/runconfig/hostconfig_unix.go index 588cfa5644..eca21a9be1 100644 --- a/runconfig/hostconfig_unix.go +++ b/runconfig/hostconfig_unix.go @@ -13,7 +13,7 @@ import ( // DefaultDaemonNetworkMode returns the default network stack the daemon should // use. func DefaultDaemonNetworkMode() container.NetworkMode { - return container.NetworkMode("bridge") + return "bridge" } // IsPreDefinedNetwork indicates if a network is predefined by the daemon @@ -25,24 +25,16 @@ func IsPreDefinedNetwork(network string) bool { // validateNetMode ensures that the various combinations of requested // network settings are valid. func validateNetMode(c *container.Config, hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - err := validateNetContainerMode(c, hc) if err != nil { return err } - if hc.UTSMode.IsHost() && c.Hostname != "" { return ErrConflictUTSHostname } - if hc.NetworkMode.IsHost() && len(hc.Links) > 0 { return ErrConflictHostNetworkAndLinks } - return nil } @@ -50,10 +42,6 @@ func validateNetMode(c *container.Config, hc *container.HostConfig) error { // isolation in the hostconfig structure. Linux only supports "default" // which is LXC container isolation func validateIsolation(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } if !hc.Isolation.IsValid() { return fmt.Errorf("Invalid isolation: %q - %s only supports 'default'", hc.Isolation, runtime.GOOS) } @@ -62,15 +50,9 @@ func validateIsolation(hc *container.HostConfig) error { // validateQoS performs platform specific validation of the QoS settings func validateQoS(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - if hc.IOMaximumBandwidth != 0 { return fmt.Errorf("Invalid QoS settings: %s does not support configuration of maximum bandwidth", runtime.GOOS) } - if hc.IOMaximumIOps != 0 { return fmt.Errorf("Invalid QoS settings: %s does not support configuration of maximum IOPs", runtime.GOOS) } @@ -80,15 +62,9 @@ func validateQoS(hc *container.HostConfig) error { // validateResources performs platform specific validation of the resource settings // cpu-rt-runtime and cpu-rt-period can not be greater than their parent, cpu-rt-runtime requires sys_nice func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } - if (hc.Resources.CPURealtimePeriod != 0 || hc.Resources.CPURealtimeRuntime != 0) && !si.CPURealtime { return fmt.Errorf("Your kernel does not support CPU real-time scheduler") } - if hc.Resources.CPURealtimePeriod != 0 && hc.Resources.CPURealtimeRuntime != 0 && hc.Resources.CPURealtimeRuntime > hc.Resources.CPURealtimePeriod { return fmt.Errorf("cpu real-time runtime cannot be higher than cpu real-time period") } @@ -96,11 +72,11 @@ func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error { } // validatePrivileged performs platform specific validation of the Privileged setting -func validatePrivileged(hc *container.HostConfig) error { +func validatePrivileged(_ *container.HostConfig) error { return nil } // validateReadonlyRootfs performs platform specific validation of the ReadonlyRootfs setting -func validateReadonlyRootfs(hc *container.HostConfig) error { +func validateReadonlyRootfs(_ *container.HostConfig) error { return nil } diff --git a/runconfig/hostconfig_windows.go b/runconfig/hostconfig_windows.go index 33a4668af1..91e27eac5e 100644 --- a/runconfig/hostconfig_windows.go +++ b/runconfig/hostconfig_windows.go @@ -10,7 +10,7 @@ import ( // DefaultDaemonNetworkMode returns the default network stack the daemon should // use. func DefaultDaemonNetworkMode() container.NetworkMode { - return container.NetworkMode("nat") + return "nat" } // IsPreDefinedNetwork indicates if a network is predefined by the daemon @@ -21,19 +21,12 @@ func IsPreDefinedNetwork(network string) bool { // validateNetMode ensures that the various combinations of requested // network settings are valid. func validateNetMode(c *container.Config, hc *container.HostConfig) error { - if hc == nil { - return nil - } - - err := validateNetContainerMode(c, hc) - if err != nil { + if err := validateNetContainerMode(c, hc); err != nil { return err } - if hc.NetworkMode.IsContainer() && hc.Isolation.IsHyperV() { return fmt.Errorf("Using the network stack of another container is not supported while using Hyper-V Containers") } - return nil } @@ -41,10 +34,6 @@ func validateNetMode(c *container.Config, hc *container.HostConfig) error { // isolation in the hostconfig structure. Windows supports 'default' (or // blank), 'process', or 'hyperv'. func validateIsolation(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } if !hc.Isolation.IsValid() { return fmt.Errorf("Invalid isolation: %q. Windows supports 'default', 'process', or 'hyperv'", hc.Isolation) } @@ -52,16 +41,12 @@ func validateIsolation(hc *container.HostConfig) error { } // validateQoS performs platform specific validation of the Qos settings -func validateQoS(hc *container.HostConfig) error { +func validateQoS(_ *container.HostConfig) error { return nil } // validateResources performs platform specific validation of the resource settings -func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } +func validateResources(hc *container.HostConfig, _ *sysinfo.SysInfo) error { if hc.Resources.CPURealtimePeriod != 0 { return fmt.Errorf("Windows does not support CPU real-time period") } @@ -73,10 +58,6 @@ func validateResources(hc *container.HostConfig, si *sysinfo.SysInfo) error { // validatePrivileged performs platform specific validation of the Privileged setting func validatePrivileged(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } if hc.Privileged { return fmt.Errorf("Windows does not support privileged mode") } @@ -85,10 +66,6 @@ func validatePrivileged(hc *container.HostConfig) error { // validateReadonlyRootfs performs platform specific validation of the ReadonlyRootfs setting func validateReadonlyRootfs(hc *container.HostConfig) error { - // We may not be passed a host config, such as in the case of docker commit - if hc == nil { - return nil - } if hc.ReadonlyRootfs { return fmt.Errorf("Windows does not support root filesystem in read-only mode") }