github.com/ruphin/docker@v1.10.1/daemon/daemon_unix.go (about)

     1  // +build linux freebsd
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strconv"
    12  	"strings"
    13  	"syscall"
    14  
    15  	"github.com/Sirupsen/logrus"
    16  	"github.com/docker/docker/container"
    17  	derr "github.com/docker/docker/errors"
    18  	"github.com/docker/docker/image"
    19  	"github.com/docker/docker/layer"
    20  	"github.com/docker/docker/pkg/idtools"
    21  	"github.com/docker/docker/pkg/parsers"
    22  	"github.com/docker/docker/pkg/parsers/kernel"
    23  	"github.com/docker/docker/pkg/sysinfo"
    24  	"github.com/docker/docker/reference"
    25  	"github.com/docker/docker/runconfig"
    26  	runconfigopts "github.com/docker/docker/runconfig/opts"
    27  	pblkiodev "github.com/docker/engine-api/types/blkiodev"
    28  	containertypes "github.com/docker/engine-api/types/container"
    29  	"github.com/docker/libnetwork"
    30  	nwconfig "github.com/docker/libnetwork/config"
    31  	"github.com/docker/libnetwork/drivers/bridge"
    32  	"github.com/docker/libnetwork/ipamutils"
    33  	"github.com/docker/libnetwork/netlabel"
    34  	"github.com/docker/libnetwork/options"
    35  	"github.com/docker/libnetwork/types"
    36  	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
    37  	"github.com/opencontainers/runc/libcontainer/label"
    38  	"github.com/opencontainers/runc/libcontainer/user"
    39  )
    40  
    41  const (
    42  	// See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
    43  	linuxMinCPUShares = 2
    44  	linuxMaxCPUShares = 262144
    45  	platformSupported = true
    46  	// It's not kernel limit, we want this 4M limit to supply a reasonable functional container
    47  	linuxMinMemory = 4194304
    48  	// constants for remapped root settings
    49  	defaultIDSpecifier string = "default"
    50  	defaultRemappedID  string = "dockremap"
    51  )
    52  
    53  func getBlkioWeightDevices(config *containertypes.HostConfig) ([]*blkiodev.WeightDevice, error) {
    54  	var stat syscall.Stat_t
    55  	var blkioWeightDevices []*blkiodev.WeightDevice
    56  
    57  	for _, weightDevice := range config.BlkioWeightDevice {
    58  		if err := syscall.Stat(weightDevice.Path, &stat); err != nil {
    59  			return nil, err
    60  		}
    61  		weightDevice := blkiodev.NewWeightDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), weightDevice.Weight, 0)
    62  		blkioWeightDevices = append(blkioWeightDevices, weightDevice)
    63  	}
    64  
    65  	return blkioWeightDevices, nil
    66  }
    67  
    68  func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
    69  	var (
    70  		labelOpts []string
    71  		err       error
    72  	)
    73  
    74  	for _, opt := range config.SecurityOpt {
    75  		con := strings.SplitN(opt, ":", 2)
    76  		if len(con) == 1 {
    77  			return fmt.Errorf("Invalid --security-opt: %q", opt)
    78  		}
    79  		switch con[0] {
    80  		case "label":
    81  			labelOpts = append(labelOpts, con[1])
    82  		case "apparmor":
    83  			container.AppArmorProfile = con[1]
    84  		case "seccomp":
    85  			container.SeccompProfile = con[1]
    86  		default:
    87  			return fmt.Errorf("Invalid --security-opt: %q", opt)
    88  		}
    89  	}
    90  
    91  	container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts)
    92  	return err
    93  }
    94  
    95  func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
    96  	var blkioReadIOpsDevice []*blkiodev.ThrottleDevice
    97  	var stat syscall.Stat_t
    98  
    99  	for _, iopsDevice := range config.BlkioDeviceReadIOps {
   100  		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
   101  			return nil, err
   102  		}
   103  		readIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
   104  		blkioReadIOpsDevice = append(blkioReadIOpsDevice, readIOpsDevice)
   105  	}
   106  
   107  	return blkioReadIOpsDevice, nil
   108  }
   109  
   110  func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
   111  	var blkioWriteIOpsDevice []*blkiodev.ThrottleDevice
   112  	var stat syscall.Stat_t
   113  
   114  	for _, iopsDevice := range config.BlkioDeviceWriteIOps {
   115  		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
   116  			return nil, err
   117  		}
   118  		writeIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
   119  		blkioWriteIOpsDevice = append(blkioWriteIOpsDevice, writeIOpsDevice)
   120  	}
   121  
   122  	return blkioWriteIOpsDevice, nil
   123  }
   124  
   125  func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
   126  	var blkioReadBpsDevice []*blkiodev.ThrottleDevice
   127  	var stat syscall.Stat_t
   128  
   129  	for _, bpsDevice := range config.BlkioDeviceReadBps {
   130  		if err := syscall.Stat(bpsDevice.Path, &stat); err != nil {
   131  			return nil, err
   132  		}
   133  		readBpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), bpsDevice.Rate)
   134  		blkioReadBpsDevice = append(blkioReadBpsDevice, readBpsDevice)
   135  	}
   136  
   137  	return blkioReadBpsDevice, nil
   138  }
   139  
   140  func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
   141  	var blkioWriteBpsDevice []*blkiodev.ThrottleDevice
   142  	var stat syscall.Stat_t
   143  
   144  	for _, bpsDevice := range config.BlkioDeviceWriteBps {
   145  		if err := syscall.Stat(bpsDevice.Path, &stat); err != nil {
   146  			return nil, err
   147  		}
   148  		writeBpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), bpsDevice.Rate)
   149  		blkioWriteBpsDevice = append(blkioWriteBpsDevice, writeBpsDevice)
   150  	}
   151  
   152  	return blkioWriteBpsDevice, nil
   153  }
   154  
   155  func checkKernelVersion(k, major, minor int) bool {
   156  	if v, err := kernel.GetKernelVersion(); err != nil {
   157  		logrus.Warnf("%s", err)
   158  	} else {
   159  		if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: k, Major: major, Minor: minor}) < 0 {
   160  			return false
   161  		}
   162  	}
   163  	return true
   164  }
   165  
   166  func checkKernel() error {
   167  	// Check for unsupported kernel versions
   168  	// FIXME: it would be cleaner to not test for specific versions, but rather
   169  	// test for specific functionalities.
   170  	// Unfortunately we can't test for the feature "does not cause a kernel panic"
   171  	// without actually causing a kernel panic, so we need this workaround until
   172  	// the circumstances of pre-3.10 crashes are clearer.
   173  	// For details see https://github.com/docker/docker/issues/407
   174  	if !checkKernelVersion(3, 10, 0) {
   175  		v, _ := kernel.GetKernelVersion()
   176  		if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
   177  			logrus.Warnf("Your Linux kernel version %s can be unstable running docker. Please upgrade your kernel to 3.10.0.", v.String())
   178  		}
   179  	}
   180  	return nil
   181  }
   182  
   183  // adaptContainerSettings is called during container creation to modify any
   184  // settings necessary in the HostConfig structure.
   185  func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
   186  	if adjustCPUShares && hostConfig.CPUShares > 0 {
   187  		// Handle unsupported CPUShares
   188  		if hostConfig.CPUShares < linuxMinCPUShares {
   189  			logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, linuxMinCPUShares)
   190  			hostConfig.CPUShares = linuxMinCPUShares
   191  		} else if hostConfig.CPUShares > linuxMaxCPUShares {
   192  			logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, linuxMaxCPUShares)
   193  			hostConfig.CPUShares = linuxMaxCPUShares
   194  		}
   195  	}
   196  	if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 {
   197  		// By default, MemorySwap is set to twice the size of Memory.
   198  		hostConfig.MemorySwap = hostConfig.Memory * 2
   199  	}
   200  	if hostConfig.ShmSize == 0 {
   201  		hostConfig.ShmSize = container.DefaultSHMSize
   202  	}
   203  	var err error
   204  	if hostConfig.SecurityOpt == nil {
   205  		hostConfig.SecurityOpt, err = daemon.generateSecurityOpt(hostConfig.IpcMode, hostConfig.PidMode)
   206  		if err != nil {
   207  			return err
   208  		}
   209  	}
   210  	if hostConfig.MemorySwappiness == nil {
   211  		defaultSwappiness := int64(-1)
   212  		hostConfig.MemorySwappiness = &defaultSwappiness
   213  	}
   214  	if hostConfig.OomKillDisable == nil {
   215  		defaultOomKillDisable := false
   216  		hostConfig.OomKillDisable = &defaultOomKillDisable
   217  	}
   218  
   219  	return nil
   220  }
   221  
   222  func verifyContainerResources(resources *containertypes.Resources) ([]string, error) {
   223  	warnings := []string{}
   224  	sysInfo := sysinfo.New(true)
   225  
   226  	// memory subsystem checks and adjustments
   227  	if resources.Memory != 0 && resources.Memory < linuxMinMemory {
   228  		return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
   229  	}
   230  	if resources.Memory > 0 && !sysInfo.MemoryLimit {
   231  		warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
   232  		logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.")
   233  		resources.Memory = 0
   234  		resources.MemorySwap = -1
   235  	}
   236  	if resources.Memory > 0 && resources.MemorySwap != -1 && !sysInfo.SwapLimit {
   237  		warnings = append(warnings, "Your kernel does not support swap limit capabilities, memory limited without swap.")
   238  		logrus.Warnf("Your kernel does not support swap limit capabilities, memory limited without swap.")
   239  		resources.MemorySwap = -1
   240  	}
   241  	if resources.Memory > 0 && resources.MemorySwap > 0 && resources.MemorySwap < resources.Memory {
   242  		return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.")
   243  	}
   244  	if resources.Memory == 0 && resources.MemorySwap > 0 {
   245  		return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage.")
   246  	}
   247  	if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 && !sysInfo.MemorySwappiness {
   248  		warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
   249  		logrus.Warnf("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
   250  		resources.MemorySwappiness = nil
   251  	}
   252  	if resources.MemorySwappiness != nil {
   253  		swappiness := *resources.MemorySwappiness
   254  		if swappiness < -1 || swappiness > 100 {
   255  			return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100.", swappiness)
   256  		}
   257  	}
   258  	if resources.MemoryReservation > 0 && !sysInfo.MemoryReservation {
   259  		warnings = append(warnings, "Your kernel does not support memory soft limit capabilities. Limitation discarded.")
   260  		logrus.Warnf("Your kernel does not support memory soft limit capabilities. Limitation discarded.")
   261  		resources.MemoryReservation = 0
   262  	}
   263  	if resources.Memory > 0 && resources.MemoryReservation > 0 && resources.Memory < resources.MemoryReservation {
   264  		return warnings, fmt.Errorf("Minimum memory limit should be larger than memory reservation limit, see usage.")
   265  	}
   266  	if resources.KernelMemory > 0 && !sysInfo.KernelMemory {
   267  		warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
   268  		logrus.Warnf("Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
   269  		resources.KernelMemory = 0
   270  	}
   271  	if resources.KernelMemory > 0 && resources.KernelMemory < linuxMinMemory {
   272  		return warnings, fmt.Errorf("Minimum kernel memory limit allowed is 4MB")
   273  	}
   274  	if resources.KernelMemory > 0 && !checkKernelVersion(4, 0, 0) {
   275  		warnings = append(warnings, "You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
   276  		logrus.Warnf("You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won't work as expected and can cause your system to be unstable.")
   277  	}
   278  	if resources.OomKillDisable != nil && !sysInfo.OomKillDisable {
   279  		// only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
   280  		// warning the caller if they already wanted the feature to be off
   281  		if *resources.OomKillDisable {
   282  			warnings = append(warnings, "Your kernel does not support OomKillDisable, OomKillDisable discarded.")
   283  			logrus.Warnf("Your kernel does not support OomKillDisable, OomKillDisable discarded.")
   284  		}
   285  		resources.OomKillDisable = nil
   286  	}
   287  
   288  	// cpu subsystem checks and adjustments
   289  	if resources.CPUShares > 0 && !sysInfo.CPUShares {
   290  		warnings = append(warnings, "Your kernel does not support CPU shares. Shares discarded.")
   291  		logrus.Warnf("Your kernel does not support CPU shares. Shares discarded.")
   292  		resources.CPUShares = 0
   293  	}
   294  	if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
   295  		warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.")
   296  		logrus.Warnf("Your kernel does not support CPU cfs period. Period discarded.")
   297  		resources.CPUPeriod = 0
   298  	}
   299  	if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
   300  		warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.")
   301  		logrus.Warnf("Your kernel does not support CPU cfs quota. Quota discarded.")
   302  		resources.CPUQuota = 0
   303  	}
   304  
   305  	// cpuset subsystem checks and adjustments
   306  	if (resources.CpusetCpus != "" || resources.CpusetMems != "") && !sysInfo.Cpuset {
   307  		warnings = append(warnings, "Your kernel does not support cpuset. Cpuset discarded.")
   308  		logrus.Warnf("Your kernel does not support cpuset. Cpuset discarded.")
   309  		resources.CpusetCpus = ""
   310  		resources.CpusetMems = ""
   311  	}
   312  	cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
   313  	if err != nil {
   314  		return warnings, derr.ErrorCodeInvalidCpusetCpus.WithArgs(resources.CpusetCpus)
   315  	}
   316  	if !cpusAvailable {
   317  		return warnings, derr.ErrorCodeNotAvailableCpusetCpus.WithArgs(resources.CpusetCpus, sysInfo.Cpus)
   318  	}
   319  	memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
   320  	if err != nil {
   321  		return warnings, derr.ErrorCodeInvalidCpusetMems.WithArgs(resources.CpusetMems)
   322  	}
   323  	if !memsAvailable {
   324  		return warnings, derr.ErrorCodeNotAvailableCpusetMems.WithArgs(resources.CpusetMems, sysInfo.Mems)
   325  	}
   326  
   327  	// blkio subsystem checks and adjustments
   328  	if resources.BlkioWeight > 0 && !sysInfo.BlkioWeight {
   329  		warnings = append(warnings, "Your kernel does not support Block I/O weight. Weight discarded.")
   330  		logrus.Warnf("Your kernel does not support Block I/O weight. Weight discarded.")
   331  		resources.BlkioWeight = 0
   332  	}
   333  	if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) {
   334  		return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000.")
   335  	}
   336  	if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
   337  		warnings = append(warnings, "Your kernel does not support Block I/O weight_device.")
   338  		logrus.Warnf("Your kernel does not support Block I/O weight_device. Weight-device discarded.")
   339  		resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
   340  	}
   341  	if len(resources.BlkioDeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice {
   342  		warnings = append(warnings, "Your kernel does not support Block read limit in bytes per second.")
   343  		logrus.Warnf("Your kernel does not support Block I/O read limit in bytes per second. --device-read-bps discarded.")
   344  		resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
   345  	}
   346  	if len(resources.BlkioDeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice {
   347  		warnings = append(warnings, "Your kernel does not support Block write limit in bytes per second.")
   348  		logrus.Warnf("Your kernel does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
   349  		resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
   350  	}
   351  	if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
   352  		warnings = append(warnings, "Your kernel does not support Block read limit in IO per second.")
   353  		logrus.Warnf("Your kernel does not support Block I/O read limit in IO per second. -device-read-iops discarded.")
   354  		resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
   355  	}
   356  	if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
   357  		warnings = append(warnings, "Your kernel does not support Block write limit in IO per second.")
   358  		logrus.Warnf("Your kernel does not support Block I/O write limit in IO per second. --device-write-iops discarded.")
   359  		resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
   360  	}
   361  
   362  	return warnings, nil
   363  }
   364  
   365  func usingSystemd(config *Config) bool {
   366  	for _, option := range config.ExecOptions {
   367  		key, val, err := parsers.ParseKeyValueOpt(option)
   368  		if err != nil || !strings.EqualFold(key, "native.cgroupdriver") {
   369  			continue
   370  		}
   371  		if val == "systemd" {
   372  			return true
   373  		}
   374  	}
   375  
   376  	return false
   377  }
   378  
   379  func (daemon *Daemon) usingSystemd() bool {
   380  	return usingSystemd(daemon.configStore)
   381  }
   382  
   383  // verifyPlatformContainerSettings performs platform-specific validation of the
   384  // hostconfig and config structures.
   385  func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config) ([]string, error) {
   386  	warnings := []string{}
   387  	sysInfo := sysinfo.New(true)
   388  
   389  	warnings, err := daemon.verifyExperimentalContainerSettings(hostConfig, config)
   390  	if err != nil {
   391  		return warnings, err
   392  	}
   393  
   394  	w, err := verifyContainerResources(&hostConfig.Resources)
   395  	if err != nil {
   396  		return warnings, err
   397  	}
   398  	warnings = append(warnings, w...)
   399  
   400  	if hostConfig.ShmSize < 0 {
   401  		return warnings, fmt.Errorf("SHM size must be greater then 0")
   402  	}
   403  
   404  	if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
   405  		return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000].", hostConfig.OomScoreAdj)
   406  	}
   407  	if sysInfo.IPv4ForwardingDisabled {
   408  		warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
   409  		logrus.Warnf("IPv4 forwarding is disabled. Networking will not work")
   410  	}
   411  	// check for various conflicting options with user namespaces
   412  	if daemon.configStore.RemappedRoot != "" {
   413  		if hostConfig.Privileged {
   414  			return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces.")
   415  		}
   416  		if hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsContainer() {
   417  			return warnings, fmt.Errorf("Cannot share the host or a container's network namespace when user namespaces are enabled.")
   418  		}
   419  		if hostConfig.PidMode.IsHost() {
   420  			return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled.")
   421  		}
   422  		if hostConfig.IpcMode.IsContainer() {
   423  			return warnings, fmt.Errorf("Cannot share a container's IPC namespace when user namespaces are enabled.")
   424  		}
   425  		if hostConfig.ReadonlyRootfs {
   426  			return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled.")
   427  		}
   428  	}
   429  	if hostConfig.CgroupParent != "" && daemon.usingSystemd() {
   430  		// CgroupParent for systemd cgroup should be named as "xxx.slice"
   431  		if len(hostConfig.CgroupParent) <= 6 || !strings.HasSuffix(hostConfig.CgroupParent, ".slice") {
   432  			return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
   433  		}
   434  	}
   435  	return warnings, nil
   436  }
   437  
   438  // verifyDaemonSettings performs validation of daemon config struct
   439  func verifyDaemonSettings(config *Config) error {
   440  	// Check for mutually incompatible config options
   441  	if config.bridgeConfig.Iface != "" && config.bridgeConfig.IP != "" {
   442  		return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
   443  	}
   444  	if !config.bridgeConfig.EnableIPTables && !config.bridgeConfig.InterContainerCommunication {
   445  		return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true.")
   446  	}
   447  	if !config.bridgeConfig.EnableIPTables && config.bridgeConfig.EnableIPMasq {
   448  		config.bridgeConfig.EnableIPMasq = false
   449  	}
   450  	if config.CgroupParent != "" && usingSystemd(config) {
   451  		if len(config.CgroupParent) <= 6 || !strings.HasSuffix(config.CgroupParent, ".slice") {
   452  			return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
   453  		}
   454  	}
   455  	return nil
   456  }
   457  
   458  // checkSystem validates platform-specific requirements
   459  func checkSystem() error {
   460  	if os.Geteuid() != 0 {
   461  		return fmt.Errorf("The Docker daemon needs to be run as root")
   462  	}
   463  	return checkKernel()
   464  }
   465  
   466  // configureKernelSecuritySupport configures and validate security support for the kernel
   467  func configureKernelSecuritySupport(config *Config, driverName string) error {
   468  	if config.EnableSelinuxSupport {
   469  		if selinuxEnabled() {
   470  			// As Docker on overlayFS and SELinux are incompatible at present, error on overlayfs being enabled
   471  			if driverName == "overlay" {
   472  				return fmt.Errorf("SELinux is not supported with the %s graph driver", driverName)
   473  			}
   474  			logrus.Debug("SELinux enabled successfully")
   475  		} else {
   476  			logrus.Warn("Docker could not enable SELinux on the host system")
   477  		}
   478  	} else {
   479  		selinuxSetDisabled()
   480  	}
   481  	return nil
   482  }
   483  
   484  func isBridgeNetworkDisabled(config *Config) bool {
   485  	return config.bridgeConfig.Iface == disableNetworkBridge
   486  }
   487  
   488  func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
   489  	options := []nwconfig.Option{}
   490  	if dconfig == nil {
   491  		return options, nil
   492  	}
   493  
   494  	options = append(options, nwconfig.OptionDataDir(dconfig.Root))
   495  
   496  	dd := runconfig.DefaultDaemonNetworkMode()
   497  	dn := runconfig.DefaultDaemonNetworkMode().NetworkName()
   498  	options = append(options, nwconfig.OptionDefaultDriver(string(dd)))
   499  	options = append(options, nwconfig.OptionDefaultNetwork(dn))
   500  
   501  	if strings.TrimSpace(dconfig.ClusterStore) != "" {
   502  		kv := strings.Split(dconfig.ClusterStore, "://")
   503  		if len(kv) != 2 {
   504  			return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL")
   505  		}
   506  		options = append(options, nwconfig.OptionKVProvider(kv[0]))
   507  		options = append(options, nwconfig.OptionKVProviderURL(kv[1]))
   508  	}
   509  	if len(dconfig.ClusterOpts) > 0 {
   510  		options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts))
   511  	}
   512  
   513  	if daemon.discoveryWatcher != nil {
   514  		options = append(options, nwconfig.OptionDiscoveryWatcher(daemon.discoveryWatcher))
   515  	}
   516  
   517  	if dconfig.ClusterAdvertise != "" {
   518  		options = append(options, nwconfig.OptionDiscoveryAddress(dconfig.ClusterAdvertise))
   519  	}
   520  
   521  	options = append(options, nwconfig.OptionLabels(dconfig.Labels))
   522  	options = append(options, driverOptions(dconfig)...)
   523  	return options, nil
   524  }
   525  
   526  func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
   527  	netOptions, err := daemon.networkOptions(config)
   528  	if err != nil {
   529  		return nil, err
   530  	}
   531  
   532  	controller, err := libnetwork.New(netOptions...)
   533  	if err != nil {
   534  		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
   535  	}
   536  
   537  	// Initialize default network on "null"
   538  	if _, err := controller.NewNetwork("null", "none", libnetwork.NetworkOptionPersist(false)); err != nil {
   539  		return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
   540  	}
   541  
   542  	// Initialize default network on "host"
   543  	if _, err := controller.NewNetwork("host", "host", libnetwork.NetworkOptionPersist(false)); err != nil {
   544  		return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
   545  	}
   546  
   547  	if !config.DisableBridge {
   548  		// Initialize default driver "bridge"
   549  		if err := initBridgeDriver(controller, config); err != nil {
   550  			return nil, err
   551  		}
   552  	}
   553  
   554  	return controller, nil
   555  }
   556  
   557  func driverOptions(config *Config) []nwconfig.Option {
   558  	bridgeConfig := options.Generic{
   559  		"EnableIPForwarding":  config.bridgeConfig.EnableIPForward,
   560  		"EnableIPTables":      config.bridgeConfig.EnableIPTables,
   561  		"EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy}
   562  	bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig}
   563  
   564  	dOptions := []nwconfig.Option{}
   565  	dOptions = append(dOptions, nwconfig.OptionDriverConfig("bridge", bridgeOption))
   566  	return dOptions
   567  }
   568  
   569  func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
   570  	if n, err := controller.NetworkByName("bridge"); err == nil {
   571  		if err = n.Delete(); err != nil {
   572  			return fmt.Errorf("could not delete the default bridge network: %v", err)
   573  		}
   574  	}
   575  
   576  	bridgeName := bridge.DefaultBridgeName
   577  	if config.bridgeConfig.Iface != "" {
   578  		bridgeName = config.bridgeConfig.Iface
   579  	}
   580  	netOption := map[string]string{
   581  		bridge.BridgeName:         bridgeName,
   582  		bridge.DefaultBridge:      strconv.FormatBool(true),
   583  		netlabel.DriverMTU:        strconv.Itoa(config.Mtu),
   584  		bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq),
   585  		bridge.EnableICC:          strconv.FormatBool(config.bridgeConfig.InterContainerCommunication),
   586  	}
   587  
   588  	// --ip processing
   589  	if config.bridgeConfig.DefaultIP != nil {
   590  		netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String()
   591  	}
   592  
   593  	var (
   594  		ipamV4Conf *libnetwork.IpamConf
   595  		ipamV6Conf *libnetwork.IpamConf
   596  	)
   597  
   598  	ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   599  
   600  	nw, nw6List, err := ipamutils.ElectInterfaceAddresses(bridgeName)
   601  	if err == nil {
   602  		ipamV4Conf.PreferredPool = types.GetIPNetCanonical(nw).String()
   603  		hip, _ := types.GetHostPartIP(nw.IP, nw.Mask)
   604  		if hip.IsGlobalUnicast() {
   605  			ipamV4Conf.Gateway = nw.IP.String()
   606  		}
   607  	}
   608  
   609  	if config.bridgeConfig.IP != "" {
   610  		ipamV4Conf.PreferredPool = config.bridgeConfig.IP
   611  		ip, _, err := net.ParseCIDR(config.bridgeConfig.IP)
   612  		if err != nil {
   613  			return err
   614  		}
   615  		ipamV4Conf.Gateway = ip.String()
   616  	} else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" {
   617  		logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool)
   618  	}
   619  
   620  	if config.bridgeConfig.FixedCIDR != "" {
   621  		_, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR)
   622  		if err != nil {
   623  			return err
   624  		}
   625  
   626  		ipamV4Conf.SubPool = fCIDR.String()
   627  	}
   628  
   629  	if config.bridgeConfig.DefaultGatewayIPv4 != nil {
   630  		ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String()
   631  	}
   632  
   633  	var deferIPv6Alloc bool
   634  	if config.bridgeConfig.FixedCIDRv6 != "" {
   635  		_, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6)
   636  		if err != nil {
   637  			return err
   638  		}
   639  
   640  		// In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has
   641  		// at least 48 host bits, we need to guarantee the current behavior where the containers'
   642  		// IPv6 addresses will be constructed based on the containers' interface MAC address.
   643  		// We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints
   644  		// on this network until after the driver has created the endpoint and returned the
   645  		// constructed address. Libnetwork will then reserve this address with the ipam driver.
   646  		ones, _ := fCIDRv6.Mask.Size()
   647  		deferIPv6Alloc = ones <= 80
   648  
   649  		if ipamV6Conf == nil {
   650  			ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   651  		}
   652  		ipamV6Conf.PreferredPool = fCIDRv6.String()
   653  
   654  		// In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6
   655  		// address belongs to the same network, we need to inform libnetwork about it, so
   656  		// that it can be reserved with IPAM and it will not be given away to somebody else
   657  		for _, nw6 := range nw6List {
   658  			if fCIDRv6.Contains(nw6.IP) {
   659  				ipamV6Conf.Gateway = nw6.IP.String()
   660  				break
   661  			}
   662  		}
   663  	}
   664  
   665  	if config.bridgeConfig.DefaultGatewayIPv6 != nil {
   666  		if ipamV6Conf == nil {
   667  			ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
   668  		}
   669  		ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String()
   670  	}
   671  
   672  	v4Conf := []*libnetwork.IpamConf{ipamV4Conf}
   673  	v6Conf := []*libnetwork.IpamConf{}
   674  	if ipamV6Conf != nil {
   675  		v6Conf = append(v6Conf, ipamV6Conf)
   676  	}
   677  	// Initialize default network on "bridge" with the same name
   678  	_, err = controller.NewNetwork("bridge", "bridge",
   679  		libnetwork.NetworkOptionGeneric(options.Generic{
   680  			netlabel.GenericData: netOption,
   681  			netlabel.EnableIPv6:  config.bridgeConfig.EnableIPv6,
   682  		}),
   683  		libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   684  		libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))
   685  	if err != nil {
   686  		return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
   687  	}
   688  	return nil
   689  }
   690  
   691  // setupInitLayer populates a directory with mountpoints suitable
   692  // for bind-mounting dockerinit into the container. The mountpoint is simply an
   693  // empty file at /.dockerinit
   694  //
   695  // This extra layer is used by all containers as the top-most ro layer. It protects
   696  // the container from unwanted side-effects on the rw layer.
   697  func setupInitLayer(initLayer string, rootUID, rootGID int) error {
   698  	for pth, typ := range map[string]string{
   699  		"/dev/pts":         "dir",
   700  		"/dev/shm":         "dir",
   701  		"/proc":            "dir",
   702  		"/sys":             "dir",
   703  		"/.dockerinit":     "file",
   704  		"/.dockerenv":      "file",
   705  		"/etc/resolv.conf": "file",
   706  		"/etc/hosts":       "file",
   707  		"/etc/hostname":    "file",
   708  		"/dev/console":     "file",
   709  		"/etc/mtab":        "/proc/mounts",
   710  	} {
   711  		parts := strings.Split(pth, "/")
   712  		prev := "/"
   713  		for _, p := range parts[1:] {
   714  			prev = filepath.Join(prev, p)
   715  			syscall.Unlink(filepath.Join(initLayer, prev))
   716  		}
   717  
   718  		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
   719  			if os.IsNotExist(err) {
   720  				if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil {
   721  					return err
   722  				}
   723  				switch typ {
   724  				case "dir":
   725  					if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil {
   726  						return err
   727  					}
   728  				case "file":
   729  					f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
   730  					if err != nil {
   731  						return err
   732  					}
   733  					f.Chown(rootUID, rootGID)
   734  					f.Close()
   735  				default:
   736  					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
   737  						return err
   738  					}
   739  				}
   740  			} else {
   741  				return err
   742  			}
   743  		}
   744  	}
   745  
   746  	// Layer is ready to use, if it wasn't before.
   747  	return nil
   748  }
   749  
   750  // Parse the remapped root (user namespace) option, which can be one of:
   751  //   username            - valid username from /etc/passwd
   752  //   username:groupname  - valid username; valid groupname from /etc/group
   753  //   uid                 - 32-bit unsigned int valid Linux UID value
   754  //   uid:gid             - uid value; 32-bit unsigned int Linux GID value
   755  //
   756  //  If no groupname is specified, and a username is specified, an attempt
   757  //  will be made to lookup a gid for that username as a groupname
   758  //
   759  //  If names are used, they are verified to exist in passwd/group
   760  func parseRemappedRoot(usergrp string) (string, string, error) {
   761  
   762  	var (
   763  		userID, groupID     int
   764  		username, groupname string
   765  	)
   766  
   767  	idparts := strings.Split(usergrp, ":")
   768  	if len(idparts) > 2 {
   769  		return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp)
   770  	}
   771  
   772  	if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil {
   773  		// must be a uid; take it as valid
   774  		userID = int(uid)
   775  		luser, err := user.LookupUid(userID)
   776  		if err != nil {
   777  			return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err)
   778  		}
   779  		username = luser.Name
   780  		if len(idparts) == 1 {
   781  			// if the uid was numeric and no gid was specified, take the uid as the gid
   782  			groupID = userID
   783  			lgrp, err := user.LookupGid(groupID)
   784  			if err != nil {
   785  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err)
   786  			}
   787  			groupname = lgrp.Name
   788  		}
   789  	} else {
   790  		lookupName := idparts[0]
   791  		// special case: if the user specified "default", they want Docker to create or
   792  		// use (after creation) the "dockremap" user/group for root remapping
   793  		if lookupName == defaultIDSpecifier {
   794  			lookupName = defaultRemappedID
   795  		}
   796  		luser, err := user.LookupUser(lookupName)
   797  		if err != nil && idparts[0] != defaultIDSpecifier {
   798  			// error if the name requested isn't the special "dockremap" ID
   799  			return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err)
   800  		} else if err != nil {
   801  			// special case-- if the username == "default", then we have been asked
   802  			// to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid}
   803  			// ranges will be used for the user and group mappings in user namespaced containers
   804  			_, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID)
   805  			if err == nil {
   806  				return defaultRemappedID, defaultRemappedID, nil
   807  			}
   808  			return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err)
   809  		}
   810  		userID = luser.Uid
   811  		username = luser.Name
   812  		if len(idparts) == 1 {
   813  			// we only have a string username, and no group specified; look up gid from username as group
   814  			group, err := user.LookupGroup(lookupName)
   815  			if err != nil {
   816  				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err)
   817  			}
   818  			groupID = group.Gid
   819  			groupname = group.Name
   820  		}
   821  	}
   822  
   823  	if len(idparts) == 2 {
   824  		// groupname or gid is separately specified and must be resolved
   825  		// to a unsigned 32-bit gid
   826  		if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil {
   827  			// must be a gid, take it as valid
   828  			groupID = int(gid)
   829  			lgrp, err := user.LookupGid(groupID)
   830  			if err != nil {
   831  				return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err)
   832  			}
   833  			groupname = lgrp.Name
   834  		} else {
   835  			// not a number; attempt a lookup
   836  			group, err := user.LookupGroup(idparts[1])
   837  			if err != nil {
   838  				return "", "", fmt.Errorf("Error during gid lookup for %q: %v", idparts[1], err)
   839  			}
   840  			groupID = group.Gid
   841  			groupname = idparts[1]
   842  		}
   843  	}
   844  	return username, groupname, nil
   845  }
   846  
   847  func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
   848  	if runtime.GOOS != "linux" && config.RemappedRoot != "" {
   849  		return nil, nil, fmt.Errorf("User namespaces are only supported on Linux")
   850  	}
   851  
   852  	// if the daemon was started with remapped root option, parse
   853  	// the config option to the int uid,gid values
   854  	var (
   855  		uidMaps, gidMaps []idtools.IDMap
   856  	)
   857  	if config.RemappedRoot != "" {
   858  		username, groupname, err := parseRemappedRoot(config.RemappedRoot)
   859  		if err != nil {
   860  			return nil, nil, err
   861  		}
   862  		if username == "root" {
   863  			// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
   864  			// effectively
   865  			logrus.Warnf("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
   866  			return uidMaps, gidMaps, nil
   867  		}
   868  		logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
   869  		// update remapped root setting now that we have resolved them to actual names
   870  		config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
   871  
   872  		uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname)
   873  		if err != nil {
   874  			return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err)
   875  		}
   876  	}
   877  	return uidMaps, gidMaps, nil
   878  }
   879  
   880  func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
   881  	config.Root = rootDir
   882  	// the docker root metadata directory needs to have execute permissions for all users (o+x)
   883  	// so that syscalls executing as non-root, operating on subdirectories of the graph root
   884  	// (e.g. mounted layers of a container) can traverse this path.
   885  	// The user namespace support will create subdirectories for the remapped root host uid:gid
   886  	// pair owned by that same uid:gid pair for proper write access to those needed metadata and
   887  	// layer content subtrees.
   888  	if _, err := os.Stat(rootDir); err == nil {
   889  		// root current exists; verify the access bits are correct by setting them
   890  		if err = os.Chmod(rootDir, 0701); err != nil {
   891  			return err
   892  		}
   893  	} else if os.IsNotExist(err) {
   894  		// no root exists yet, create it 0701 with root:root ownership
   895  		if err := os.MkdirAll(rootDir, 0701); err != nil {
   896  			return err
   897  		}
   898  	}
   899  
   900  	// if user namespaces are enabled we will create a subtree underneath the specified root
   901  	// with any/all specified remapped root uid/gid options on the daemon creating
   902  	// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
   903  	// `chdir()` to work for containers namespaced to that uid/gid)
   904  	if config.RemappedRoot != "" {
   905  		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID))
   906  		logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
   907  		// Create the root directory if it doesn't exists
   908  		if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil {
   909  			return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
   910  		}
   911  	}
   912  	return nil
   913  }
   914  
   915  // registerLinks writes the links to a file.
   916  func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
   917  	if hostConfig == nil || hostConfig.NetworkMode.IsUserDefined() {
   918  		return nil
   919  	}
   920  
   921  	for _, l := range hostConfig.Links {
   922  		name, alias, err := runconfigopts.ParseLink(l)
   923  		if err != nil {
   924  			return err
   925  		}
   926  		child, err := daemon.GetContainer(name)
   927  		if err != nil {
   928  			//An error from daemon.GetContainer() means this name could not be found
   929  			return fmt.Errorf("Could not get container for %s", name)
   930  		}
   931  		for child.HostConfig.NetworkMode.IsContainer() {
   932  			parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
   933  			child, err = daemon.GetContainer(parts[1])
   934  			if err != nil {
   935  				return fmt.Errorf("Could not get container for %s", parts[1])
   936  			}
   937  		}
   938  		if child.HostConfig.NetworkMode.IsHost() {
   939  			return runconfig.ErrConflictHostNetworkAndLinks
   940  		}
   941  		if err := daemon.registerLink(container, child, alias); err != nil {
   942  			return err
   943  		}
   944  	}
   945  
   946  	// After we load all the links into the daemon
   947  	// set them to nil on the hostconfig
   948  	return container.WriteHostConfig()
   949  }
   950  
   951  // conditionalMountOnStart is a platform specific helper function during the
   952  // container start to call mount.
   953  func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
   954  	return daemon.Mount(container)
   955  }
   956  
   957  // conditionalUnmountOnCleanup is a platform specific helper function called
   958  // during the cleanup of a container to unmount.
   959  func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) {
   960  	daemon.Unmount(container)
   961  }
   962  
   963  func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error {
   964  	// Unix has no custom images to register
   965  	return nil
   966  }