Tizen_4.0 base
[platform/upstream/docker-engine.git] / daemon / daemon_unix.go
1 // +build linux freebsd
2
3 package daemon
4
5 import (
6         "bufio"
7         "bytes"
8         "fmt"
9         "io/ioutil"
10         "net"
11         "os"
12         "path/filepath"
13         "runtime"
14         "runtime/debug"
15         "strconv"
16         "strings"
17         "syscall"
18         "time"
19
20         "github.com/Sirupsen/logrus"
21         "github.com/docker/docker/api/types"
22         "github.com/docker/docker/api/types/blkiodev"
23         pblkiodev "github.com/docker/docker/api/types/blkiodev"
24         containertypes "github.com/docker/docker/api/types/container"
25         "github.com/docker/docker/container"
26         "github.com/docker/docker/daemon/config"
27         "github.com/docker/docker/image"
28         "github.com/docker/docker/opts"
29         "github.com/docker/docker/pkg/idtools"
30         "github.com/docker/docker/pkg/parsers"
31         "github.com/docker/docker/pkg/parsers/kernel"
32         "github.com/docker/docker/pkg/sysinfo"
33         "github.com/docker/docker/runconfig"
34         "github.com/docker/docker/volume"
35         "github.com/docker/libnetwork"
36         nwconfig "github.com/docker/libnetwork/config"
37         "github.com/docker/libnetwork/drivers/bridge"
38         "github.com/docker/libnetwork/netlabel"
39         "github.com/docker/libnetwork/netutils"
40         "github.com/docker/libnetwork/options"
41         lntypes "github.com/docker/libnetwork/types"
42         "github.com/golang/protobuf/ptypes"
43         "github.com/opencontainers/runc/libcontainer/cgroups"
44         rsystem "github.com/opencontainers/runc/libcontainer/system"
45         specs "github.com/opencontainers/runtime-spec/specs-go"
46         "github.com/opencontainers/selinux/go-selinux/label"
47         "github.com/pkg/errors"
48         "github.com/vishvananda/netlink"
49 )
50
51 const (
52         // See https://git.kernel.org/cgit/linux/kernel/git/tip/tip.git/tree/kernel/sched/sched.h?id=8cd9234c64c584432f6992fe944ca9e46ca8ea76#n269
53         linuxMinCPUShares = 2
54         linuxMaxCPUShares = 262144
55         platformSupported = true
56         // It's not kernel limit, we want this 4M limit to supply a reasonable functional container
57         linuxMinMemory = 4194304
58         // constants for remapped root settings
59         defaultIDSpecifier string = "default"
60         defaultRemappedID  string = "dockremap"
61
62         // constant for cgroup drivers
63         cgroupFsDriver      = "cgroupfs"
64         cgroupSystemdDriver = "systemd"
65 )
66
67 func getMemoryResources(config containertypes.Resources) *specs.LinuxMemory {
68         memory := specs.LinuxMemory{}
69
70         if config.Memory > 0 {
71                 limit := uint64(config.Memory)
72                 memory.Limit = &limit
73         }
74
75         if config.MemoryReservation > 0 {
76                 reservation := uint64(config.MemoryReservation)
77                 memory.Reservation = &reservation
78         }
79
80         if config.MemorySwap > 0 {
81                 swap := uint64(config.MemorySwap)
82                 memory.Swap = &swap
83         }
84
85         if config.MemorySwappiness != nil {
86                 swappiness := uint64(*config.MemorySwappiness)
87                 memory.Swappiness = &swappiness
88         }
89
90         if config.KernelMemory != 0 {
91                 kernelMemory := uint64(config.KernelMemory)
92                 memory.Kernel = &kernelMemory
93         }
94
95         return &memory
96 }
97
98 func getCPUResources(config containertypes.Resources) (*specs.LinuxCPU, error) {
99         cpu := specs.LinuxCPU{}
100
101         if config.CPUShares < 0 {
102                 return nil, fmt.Errorf("shares: invalid argument")
103         }
104         if config.CPUShares >= 0 {
105                 shares := uint64(config.CPUShares)
106                 cpu.Shares = &shares
107         }
108
109         if config.CpusetCpus != "" {
110                 cpu.Cpus = config.CpusetCpus
111         }
112
113         if config.CpusetMems != "" {
114                 cpu.Mems = config.CpusetMems
115         }
116
117         if config.NanoCPUs > 0 {
118                 // https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
119                 period := uint64(100 * time.Millisecond / time.Microsecond)
120                 quota := config.NanoCPUs * int64(period) / 1e9
121                 cpu.Period = &period
122                 cpu.Quota = &quota
123         }
124
125         if config.CPUPeriod != 0 {
126                 period := uint64(config.CPUPeriod)
127                 cpu.Period = &period
128         }
129
130         if config.CPUQuota != 0 {
131                 q := config.CPUQuota
132                 cpu.Quota = &q
133         }
134
135         if config.CPURealtimePeriod != 0 {
136                 period := uint64(config.CPURealtimePeriod)
137                 cpu.RealtimePeriod = &period
138         }
139
140         if config.CPURealtimeRuntime != 0 {
141                 c := config.CPURealtimeRuntime
142                 cpu.RealtimeRuntime = &c
143         }
144
145         return &cpu, nil
146 }
147
148 func getBlkioWeightDevices(config containertypes.Resources) ([]specs.LinuxWeightDevice, error) {
149         var stat syscall.Stat_t
150         var blkioWeightDevices []specs.LinuxWeightDevice
151
152         for _, weightDevice := range config.BlkioWeightDevice {
153                 if err := syscall.Stat(weightDevice.Path, &stat); err != nil {
154                         return nil, err
155                 }
156                 weight := weightDevice.Weight
157                 d := specs.LinuxWeightDevice{Weight: &weight}
158                 d.Major = int64(stat.Rdev / 256)
159                 d.Minor = int64(stat.Rdev % 256)
160                 blkioWeightDevices = append(blkioWeightDevices, d)
161         }
162
163         return blkioWeightDevices, nil
164 }
165
166 func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
167         container.NoNewPrivileges = daemon.configStore.NoNewPrivileges
168         return parseSecurityOpt(container, hostConfig)
169 }
170
171 func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
172         var (
173                 labelOpts []string
174                 err       error
175         )
176
177         for _, opt := range config.SecurityOpt {
178                 if opt == "no-new-privileges" {
179                         container.NoNewPrivileges = true
180                         continue
181                 }
182                 if opt == "disable" {
183                         labelOpts = append(labelOpts, "disable")
184                         continue
185                 }
186
187                 var con []string
188                 if strings.Contains(opt, "=") {
189                         con = strings.SplitN(opt, "=", 2)
190                 } else if strings.Contains(opt, ":") {
191                         con = strings.SplitN(opt, ":", 2)
192                         logrus.Warn("Security options with `:` as a separator are deprecated and will be completely unsupported in 17.04, use `=` instead.")
193                 }
194                 if len(con) != 2 {
195                         return fmt.Errorf("invalid --security-opt 1: %q", opt)
196                 }
197
198                 switch con[0] {
199                 case "label":
200                         labelOpts = append(labelOpts, con[1])
201                 case "apparmor":
202                         container.AppArmorProfile = con[1]
203                 case "seccomp":
204                         container.SeccompProfile = con[1]
205                 case "no-new-privileges":
206                         noNewPrivileges, err := strconv.ParseBool(con[1])
207                         if err != nil {
208                                 return fmt.Errorf("invalid --security-opt 2: %q", opt)
209                         }
210                         container.NoNewPrivileges = noNewPrivileges
211                 default:
212                         return fmt.Errorf("invalid --security-opt 2: %q", opt)
213                 }
214         }
215
216         container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts)
217         return err
218 }
219
220 func getBlkioThrottleDevices(devs []*blkiodev.ThrottleDevice) ([]specs.LinuxThrottleDevice, error) {
221         var throttleDevices []specs.LinuxThrottleDevice
222         var stat syscall.Stat_t
223
224         for _, d := range devs {
225                 if err := syscall.Stat(d.Path, &stat); err != nil {
226                         return nil, err
227                 }
228                 d := specs.LinuxThrottleDevice{Rate: d.Rate}
229                 d.Major = int64(stat.Rdev / 256)
230                 d.Minor = int64(stat.Rdev % 256)
231                 throttleDevices = append(throttleDevices, d)
232         }
233
234         return throttleDevices, nil
235 }
236
237 func checkKernel() error {
238         // Check for unsupported kernel versions
239         // FIXME: it would be cleaner to not test for specific versions, but rather
240         // test for specific functionalities.
241         // Unfortunately we can't test for the feature "does not cause a kernel panic"
242         // without actually causing a kernel panic, so we need this workaround until
243         // the circumstances of pre-3.10 crashes are clearer.
244         // For details see https://github.com/docker/docker/issues/407
245         // Docker 1.11 and above doesn't actually run on kernels older than 3.4,
246         // due to containerd-shim usage of PR_SET_CHILD_SUBREAPER (introduced in 3.4).
247         if !kernel.CheckKernelVersion(3, 10, 0) {
248                 v, _ := kernel.GetKernelVersion()
249                 if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
250                         logrus.Fatalf("Your Linux kernel version %s is not supported for running docker. Please upgrade your kernel to 3.10.0 or newer.", v.String())
251                 }
252         }
253         return nil
254 }
255
256 // adaptContainerSettings is called during container creation to modify any
257 // settings necessary in the HostConfig structure.
258 func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
259         if adjustCPUShares && hostConfig.CPUShares > 0 {
260                 // Handle unsupported CPUShares
261                 if hostConfig.CPUShares < linuxMinCPUShares {
262                         logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, linuxMinCPUShares)
263                         hostConfig.CPUShares = linuxMinCPUShares
264                 } else if hostConfig.CPUShares > linuxMaxCPUShares {
265                         logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, linuxMaxCPUShares)
266                         hostConfig.CPUShares = linuxMaxCPUShares
267                 }
268         }
269         if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 {
270                 // By default, MemorySwap is set to twice the size of Memory.
271                 hostConfig.MemorySwap = hostConfig.Memory * 2
272         }
273         if hostConfig.ShmSize == 0 {
274                 hostConfig.ShmSize = config.DefaultShmSize
275                 if daemon.configStore != nil {
276                         hostConfig.ShmSize = int64(daemon.configStore.ShmSize)
277                 }
278         }
279         var err error
280         opts, err := daemon.generateSecurityOpt(hostConfig)
281         if err != nil {
282                 return err
283         }
284         hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, opts...)
285         if hostConfig.MemorySwappiness == nil {
286                 defaultSwappiness := int64(-1)
287                 hostConfig.MemorySwappiness = &defaultSwappiness
288         }
289         if hostConfig.OomKillDisable == nil {
290                 defaultOomKillDisable := false
291                 hostConfig.OomKillDisable = &defaultOomKillDisable
292         }
293
294         return nil
295 }
296
297 func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo, update bool) ([]string, error) {
298         warnings := []string{}
299
300         // memory subsystem checks and adjustments
301         if resources.Memory != 0 && resources.Memory < linuxMinMemory {
302                 return warnings, fmt.Errorf("Minimum memory limit allowed is 4MB")
303         }
304         if resources.Memory > 0 && !sysInfo.MemoryLimit {
305                 warnings = append(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
306                 logrus.Warn("Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
307                 resources.Memory = 0
308                 resources.MemorySwap = -1
309         }
310         if resources.Memory > 0 && resources.MemorySwap != -1 && !sysInfo.SwapLimit {
311                 warnings = append(warnings, "Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.")
312                 logrus.Warn("Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.")
313                 resources.MemorySwap = -1
314         }
315         if resources.Memory > 0 && resources.MemorySwap > 0 && resources.MemorySwap < resources.Memory {
316                 return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage")
317         }
318         if resources.Memory == 0 && resources.MemorySwap > 0 && !update {
319                 return warnings, fmt.Errorf("You should always set the Memory limit when using Memoryswap limit, see usage")
320         }
321         if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 && !sysInfo.MemorySwappiness {
322                 warnings = append(warnings, "Your kernel does not support memory swappiness capabilities or the cgroup is not mounted. Memory swappiness discarded.")
323                 logrus.Warn("Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded.")
324                 resources.MemorySwappiness = nil
325         }
326         if resources.MemorySwappiness != nil {
327                 swappiness := *resources.MemorySwappiness
328                 if swappiness < -1 || swappiness > 100 {
329                         return warnings, fmt.Errorf("Invalid value: %v, valid memory swappiness range is 0-100", swappiness)
330                 }
331         }
332         if resources.MemoryReservation > 0 && !sysInfo.MemoryReservation {
333                 warnings = append(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
334                 logrus.Warn("Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
335                 resources.MemoryReservation = 0
336         }
337         if resources.MemoryReservation > 0 && resources.MemoryReservation < linuxMinMemory {
338                 return warnings, fmt.Errorf("Minimum memory reservation allowed is 4MB")
339         }
340         if resources.Memory > 0 && resources.MemoryReservation > 0 && resources.Memory < resources.MemoryReservation {
341                 return warnings, fmt.Errorf("Minimum memory limit can not be less than memory reservation limit, see usage")
342         }
343         if resources.KernelMemory > 0 && !sysInfo.KernelMemory {
344                 warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
345                 logrus.Warn("Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
346                 resources.KernelMemory = 0
347         }
348         if resources.KernelMemory > 0 && resources.KernelMemory < linuxMinMemory {
349                 return warnings, fmt.Errorf("Minimum kernel memory limit allowed is 4MB")
350         }
351         if resources.KernelMemory > 0 && !kernel.CheckKernelVersion(4, 0, 0) {
352                 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.")
353                 logrus.Warn("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.")
354         }
355         if resources.OomKillDisable != nil && !sysInfo.OomKillDisable {
356                 // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
357                 // warning the caller if they already wanted the feature to be off
358                 if *resources.OomKillDisable {
359                         warnings = append(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
360                         logrus.Warn("Your kernel does not support OomKillDisable. OomKillDisable discarded.")
361                 }
362                 resources.OomKillDisable = nil
363         }
364
365         if resources.PidsLimit != 0 && !sysInfo.PidsLimit {
366                 warnings = append(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
367                 logrus.Warn("Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
368                 resources.PidsLimit = 0
369         }
370
371         // cpu subsystem checks and adjustments
372         if resources.NanoCPUs > 0 && resources.CPUPeriod > 0 {
373                 return warnings, fmt.Errorf("Conflicting options: Nano CPUs and CPU Period cannot both be set")
374         }
375         if resources.NanoCPUs > 0 && resources.CPUQuota > 0 {
376                 return warnings, fmt.Errorf("Conflicting options: Nano CPUs and CPU Quota cannot both be set")
377         }
378         if resources.NanoCPUs > 0 && (!sysInfo.CPUCfsPeriod || !sysInfo.CPUCfsQuota) {
379                 return warnings, fmt.Errorf("NanoCPUs can not be set, as your kernel does not support CPU cfs period/quota or the cgroup is not mounted")
380         }
381         // The highest precision we could get on Linux is 0.001, by setting
382         //   cpu.cfs_period_us=1000ms
383         //   cpu.cfs_quota=1ms
384         // See the following link for details:
385         // https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt
386         // Here we don't set the lower limit and it is up to the underlying platform (e.g., Linux) to return an error.
387         // The error message is 0.01 so that this is consistent with Windows
388         if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
389                 return warnings, fmt.Errorf("Range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo.NumCPU(), sysinfo.NumCPU())
390         }
391
392         if resources.CPUShares > 0 && !sysInfo.CPUShares {
393                 warnings = append(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
394                 logrus.Warn("Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
395                 resources.CPUShares = 0
396         }
397         if resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
398                 warnings = append(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
399                 logrus.Warn("Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
400                 resources.CPUPeriod = 0
401         }
402         if resources.CPUPeriod != 0 && (resources.CPUPeriod < 1000 || resources.CPUPeriod > 1000000) {
403                 return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
404         }
405         if resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
406                 warnings = append(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
407                 logrus.Warn("Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
408                 resources.CPUQuota = 0
409         }
410         if resources.CPUQuota > 0 && resources.CPUQuota < 1000 {
411                 return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)")
412         }
413         if resources.CPUPercent > 0 {
414                 warnings = append(warnings, fmt.Sprintf("%s does not support CPU percent. Percent discarded.", runtime.GOOS))
415                 logrus.Warnf("%s does not support CPU percent. Percent discarded.", runtime.GOOS)
416                 resources.CPUPercent = 0
417         }
418
419         // cpuset subsystem checks and adjustments
420         if (resources.CpusetCpus != "" || resources.CpusetMems != "") && !sysInfo.Cpuset {
421                 warnings = append(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.")
422                 logrus.Warn("Your kernel does not support cpuset or the cgroup is not mounted. Cpuset discarded.")
423                 resources.CpusetCpus = ""
424                 resources.CpusetMems = ""
425         }
426         cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
427         if err != nil {
428                 return warnings, fmt.Errorf("Invalid value %s for cpuset cpus", resources.CpusetCpus)
429         }
430         if !cpusAvailable {
431                 return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s", resources.CpusetCpus, sysInfo.Cpus)
432         }
433         memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
434         if err != nil {
435                 return warnings, fmt.Errorf("Invalid value %s for cpuset mems", resources.CpusetMems)
436         }
437         if !memsAvailable {
438                 return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s", resources.CpusetMems, sysInfo.Mems)
439         }
440
441         // blkio subsystem checks and adjustments
442         if resources.BlkioWeight > 0 && !sysInfo.BlkioWeight {
443                 warnings = append(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
444                 logrus.Warn("Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
445                 resources.BlkioWeight = 0
446         }
447         if resources.BlkioWeight > 0 && (resources.BlkioWeight < 10 || resources.BlkioWeight > 1000) {
448                 return warnings, fmt.Errorf("Range of blkio weight is from 10 to 1000")
449         }
450         if resources.IOMaximumBandwidth != 0 || resources.IOMaximumIOps != 0 {
451                 return warnings, fmt.Errorf("Invalid QoS settings: %s does not support Maximum IO Bandwidth or Maximum IO IOps", runtime.GOOS)
452         }
453         if len(resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
454                 warnings = append(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
455                 logrus.Warn("Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
456                 resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
457         }
458         if len(resources.BlkioDeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice {
459                 warnings = append(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded.")
460                 logrus.Warn("Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded")
461                 resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
462         }
463         if len(resources.BlkioDeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice {
464                 warnings = append(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
465                 logrus.Warn("Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
466                 resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
467         }
468         if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
469                 warnings = append(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
470                 logrus.Warn("Your kernel does not support IOPS Block I/O read limit in IO or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
471                 resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
472         }
473         if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
474                 warnings = append(warnings, "Your kernel does not support IOPS Block write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
475                 logrus.Warn("Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
476                 resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
477         }
478
479         return warnings, nil
480 }
481
482 func (daemon *Daemon) getCgroupDriver() string {
483         cgroupDriver := cgroupFsDriver
484
485         if UsingSystemd(daemon.configStore) {
486                 cgroupDriver = cgroupSystemdDriver
487         }
488         return cgroupDriver
489 }
490
491 // getCD gets the raw value of the native.cgroupdriver option, if set.
492 func getCD(config *config.Config) string {
493         for _, option := range config.ExecOptions {
494                 key, val, err := parsers.ParseKeyValueOpt(option)
495                 if err != nil || !strings.EqualFold(key, "native.cgroupdriver") {
496                         continue
497                 }
498                 return val
499         }
500         return ""
501 }
502
503 // VerifyCgroupDriver validates native.cgroupdriver
504 func VerifyCgroupDriver(config *config.Config) error {
505         cd := getCD(config)
506         if cd == "" || cd == cgroupFsDriver || cd == cgroupSystemdDriver {
507                 return nil
508         }
509         return fmt.Errorf("native.cgroupdriver option %s not supported", cd)
510 }
511
512 // UsingSystemd returns true if cli option includes native.cgroupdriver=systemd
513 func UsingSystemd(config *config.Config) bool {
514         return getCD(config) == cgroupSystemdDriver
515 }
516
517 // verifyPlatformContainerSettings performs platform-specific validation of the
518 // hostconfig and config structures.
519 func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
520         var warnings []string
521         sysInfo := sysinfo.New(true)
522
523         warnings, err := daemon.verifyExperimentalContainerSettings(hostConfig, config)
524         if err != nil {
525                 return warnings, err
526         }
527
528         w, err := verifyContainerResources(&hostConfig.Resources, sysInfo, update)
529
530         // no matter err is nil or not, w could have data in itself.
531         warnings = append(warnings, w...)
532
533         if err != nil {
534                 return warnings, err
535         }
536
537         if hostConfig.ShmSize < 0 {
538                 return warnings, fmt.Errorf("SHM size can not be less than 0")
539         }
540
541         if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
542                 return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000]", hostConfig.OomScoreAdj)
543         }
544
545         // ip-forwarding does not affect container with '--net=host' (or '--net=none')
546         if sysInfo.IPv4ForwardingDisabled && !(hostConfig.NetworkMode.IsHost() || hostConfig.NetworkMode.IsNone()) {
547                 warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
548                 logrus.Warn("IPv4 forwarding is disabled. Networking will not work")
549         }
550         // check for various conflicting options with user namespaces
551         if daemon.configStore.RemappedRoot != "" && hostConfig.UsernsMode.IsPrivate() {
552                 if hostConfig.Privileged {
553                         return warnings, fmt.Errorf("Privileged mode is incompatible with user namespaces")
554                 }
555                 if hostConfig.NetworkMode.IsHost() && !hostConfig.UsernsMode.IsHost() {
556                         return warnings, fmt.Errorf("Cannot share the host's network namespace when user namespaces are enabled")
557                 }
558                 if hostConfig.PidMode.IsHost() && !hostConfig.UsernsMode.IsHost() {
559                         return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled")
560                 }
561         }
562         if hostConfig.CgroupParent != "" && UsingSystemd(daemon.configStore) {
563                 // CgroupParent for systemd cgroup should be named as "xxx.slice"
564                 if len(hostConfig.CgroupParent) <= 6 || !strings.HasSuffix(hostConfig.CgroupParent, ".slice") {
565                         return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
566                 }
567         }
568         if hostConfig.Runtime == "" {
569                 hostConfig.Runtime = daemon.configStore.GetDefaultRuntimeName()
570         }
571
572         if rt := daemon.configStore.GetRuntime(hostConfig.Runtime); rt == nil {
573                 return warnings, fmt.Errorf("Unknown runtime specified %s", hostConfig.Runtime)
574         }
575
576         for dest := range hostConfig.Tmpfs {
577                 if err := volume.ValidateTmpfsMountDestination(dest); err != nil {
578                         return warnings, err
579                 }
580         }
581
582         return warnings, nil
583 }
584
585 // reloadPlatform updates configuration with platform specific options
586 // and updates the passed attributes
587 func (daemon *Daemon) reloadPlatform(conf *config.Config, attributes map[string]string) {
588         if conf.IsValueSet("runtimes") {
589                 daemon.configStore.Runtimes = conf.Runtimes
590                 // Always set the default one
591                 daemon.configStore.Runtimes[config.StockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary}
592         }
593
594         if conf.DefaultRuntime != "" {
595                 daemon.configStore.DefaultRuntime = conf.DefaultRuntime
596         }
597
598         if conf.IsValueSet("default-shm-size") {
599                 daemon.configStore.ShmSize = conf.ShmSize
600         }
601
602         // Update attributes
603         var runtimeList bytes.Buffer
604         for name, rt := range daemon.configStore.Runtimes {
605                 if runtimeList.Len() > 0 {
606                         runtimeList.WriteRune(' ')
607                 }
608                 runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt))
609         }
610
611         attributes["runtimes"] = runtimeList.String()
612         attributes["default-runtime"] = daemon.configStore.DefaultRuntime
613         attributes["default-shm-size"] = fmt.Sprintf("%d", daemon.configStore.ShmSize)
614 }
615
616 // verifyDaemonSettings performs validation of daemon config struct
617 func verifyDaemonSettings(conf *config.Config) error {
618         // Check for mutually incompatible config options
619         if conf.BridgeConfig.Iface != "" && conf.BridgeConfig.IP != "" {
620                 return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one")
621         }
622         if !conf.BridgeConfig.EnableIPTables && !conf.BridgeConfig.InterContainerCommunication {
623                 return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true")
624         }
625         if !conf.BridgeConfig.EnableIPTables && conf.BridgeConfig.EnableIPMasq {
626                 conf.BridgeConfig.EnableIPMasq = false
627         }
628         if err := VerifyCgroupDriver(conf); err != nil {
629                 return err
630         }
631         if conf.CgroupParent != "" && UsingSystemd(conf) {
632                 if len(conf.CgroupParent) <= 6 || !strings.HasSuffix(conf.CgroupParent, ".slice") {
633                         return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
634                 }
635         }
636
637         if conf.DefaultRuntime == "" {
638                 conf.DefaultRuntime = config.StockRuntimeName
639         }
640         if conf.Runtimes == nil {
641                 conf.Runtimes = make(map[string]types.Runtime)
642         }
643         conf.Runtimes[config.StockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary}
644         conf.Runtimes["bare"] = types.Runtime{}
645
646         return nil
647 }
648
649 // checkSystem validates platform-specific requirements
650 func checkSystem() error {
651         if os.Geteuid() != 0 {
652                 return fmt.Errorf("The Docker daemon needs to be run as root")
653         }
654         return checkKernel()
655 }
656
657 // configureMaxThreads sets the Go runtime max threads threshold
658 // which is 90% of the kernel setting from /proc/sys/kernel/threads-max
659 func configureMaxThreads(config *config.Config) error {
660         mt, err := ioutil.ReadFile("/proc/sys/kernel/threads-max")
661         if err != nil {
662                 return err
663         }
664         mtint, err := strconv.Atoi(strings.TrimSpace(string(mt)))
665         if err != nil {
666                 return err
667         }
668         maxThreads := (mtint / 100) * 90
669         debug.SetMaxThreads(maxThreads)
670         logrus.Debugf("Golang's threads limit set to %d", maxThreads)
671         return nil
672 }
673
674 func overlaySupportsSelinux() (bool, error) {
675         f, err := os.Open("/proc/kallsyms")
676         if err != nil {
677                 if os.IsNotExist(err) {
678                         return false, nil
679                 }
680                 return false, err
681         }
682         defer f.Close()
683
684         var symAddr, symType, symName, text string
685
686         s := bufio.NewScanner(f)
687         for s.Scan() {
688                 if err := s.Err(); err != nil {
689                         return false, err
690                 }
691
692                 text = s.Text()
693                 if _, err := fmt.Sscanf(text, "%s %s %s", &symAddr, &symType, &symName); err != nil {
694                         return false, fmt.Errorf("Scanning '%s' failed: %s", text, err)
695                 }
696
697                 // Check for presence of symbol security_inode_copy_up.
698                 if symName == "security_inode_copy_up" {
699                         return true, nil
700                 }
701         }
702         return false, nil
703 }
704
705 // configureKernelSecuritySupport configures and validates security support for the kernel
706 func configureKernelSecuritySupport(config *config.Config, driverNames []string) error {
707         if config.EnableSelinuxSupport {
708                 if !selinuxEnabled() {
709                         logrus.Warn("Docker could not enable SELinux on the host system")
710                         return nil
711                 }
712
713                 overlayFound := false
714                 for _, d := range driverNames {
715                         if d == "overlay" || d == "overlay2" {
716                                 overlayFound = true
717                                 break
718                         }
719                 }
720
721                 if overlayFound {
722                         // If driver is overlay or overlay2, make sure kernel
723                         // supports selinux with overlay.
724                         supported, err := overlaySupportsSelinux()
725                         if err != nil {
726                                 return err
727                         }
728
729                         if !supported {
730                                 logrus.Warnf("SELinux is not supported with the %v graph driver on this kernel", driverNames)
731                         }
732                 }
733         } else {
734                 selinuxSetDisabled()
735         }
736         return nil
737 }
738
739 func (daemon *Daemon) initNetworkController(config *config.Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
740         netOptions, err := daemon.networkOptions(config, daemon.PluginStore, activeSandboxes)
741         if err != nil {
742                 return nil, err
743         }
744
745         controller, err := libnetwork.New(netOptions...)
746         if err != nil {
747                 return nil, fmt.Errorf("error obtaining controller instance: %v", err)
748         }
749
750         if len(activeSandboxes) > 0 {
751                 logrus.Info("There are old running containers, the network config will not take affect")
752                 return controller, nil
753         }
754
755         // Initialize default network on "null"
756         if n, _ := controller.NetworkByName("none"); n == nil {
757                 if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(true)); err != nil {
758                         return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
759                 }
760         }
761
762         // Initialize default network on "host"
763         if n, _ := controller.NetworkByName("host"); n == nil {
764                 if _, err := controller.NewNetwork("host", "host", "", libnetwork.NetworkOptionPersist(true)); err != nil {
765                         return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
766                 }
767         }
768
769         // Clear stale bridge network
770         if n, err := controller.NetworkByName("bridge"); err == nil {
771                 if err = n.Delete(); err != nil {
772                         return nil, fmt.Errorf("could not delete the default bridge network: %v", err)
773                 }
774         }
775
776         if !config.DisableBridge {
777                 // Initialize default driver "bridge"
778                 if err := initBridgeDriver(controller, config); err != nil {
779                         return nil, err
780                 }
781         } else {
782                 removeDefaultBridgeInterface()
783         }
784
785         return controller, nil
786 }
787
788 func driverOptions(config *config.Config) []nwconfig.Option {
789         bridgeConfig := options.Generic{
790                 "EnableIPForwarding":  config.BridgeConfig.EnableIPForward,
791                 "EnableIPTables":      config.BridgeConfig.EnableIPTables,
792                 "EnableUserlandProxy": config.BridgeConfig.EnableUserlandProxy,
793                 "UserlandProxyPath":   config.BridgeConfig.UserlandProxyPath}
794         bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig}
795
796         dOptions := []nwconfig.Option{}
797         dOptions = append(dOptions, nwconfig.OptionDriverConfig("bridge", bridgeOption))
798         return dOptions
799 }
800
801 func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error {
802         bridgeName := bridge.DefaultBridgeName
803         if config.BridgeConfig.Iface != "" {
804                 bridgeName = config.BridgeConfig.Iface
805         }
806         netOption := map[string]string{
807                 bridge.BridgeName:         bridgeName,
808                 bridge.DefaultBridge:      strconv.FormatBool(true),
809                 netlabel.DriverMTU:        strconv.Itoa(config.Mtu),
810                 bridge.EnableIPMasquerade: strconv.FormatBool(config.BridgeConfig.EnableIPMasq),
811                 bridge.EnableICC:          strconv.FormatBool(config.BridgeConfig.InterContainerCommunication),
812         }
813
814         // --ip processing
815         if config.BridgeConfig.DefaultIP != nil {
816                 netOption[bridge.DefaultBindingIP] = config.BridgeConfig.DefaultIP.String()
817         }
818
819         var (
820                 ipamV4Conf *libnetwork.IpamConf
821                 ipamV6Conf *libnetwork.IpamConf
822         )
823
824         ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
825
826         nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName)
827         if err != nil {
828                 return errors.Wrap(err, "list bridge addresses failed")
829         }
830
831         nw := nwList[0]
832         if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" {
833                 _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR)
834                 if err != nil {
835                         return errors.Wrap(err, "parse CIDR failed")
836                 }
837                 // Iterate through in case there are multiple addresses for the bridge
838                 for _, entry := range nwList {
839                         if fCIDR.Contains(entry.IP) {
840                                 nw = entry
841                                 break
842                         }
843                 }
844         }
845
846         ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
847         hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
848         if hip.IsGlobalUnicast() {
849                 ipamV4Conf.Gateway = nw.IP.String()
850         }
851
852         if config.BridgeConfig.IP != "" {
853                 ipamV4Conf.PreferredPool = config.BridgeConfig.IP
854                 ip, _, err := net.ParseCIDR(config.BridgeConfig.IP)
855                 if err != nil {
856                         return err
857                 }
858                 ipamV4Conf.Gateway = ip.String()
859         } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" {
860                 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)
861         }
862
863         if config.BridgeConfig.FixedCIDR != "" {
864                 _, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR)
865                 if err != nil {
866                         return err
867                 }
868
869                 ipamV4Conf.SubPool = fCIDR.String()
870         }
871
872         if config.BridgeConfig.DefaultGatewayIPv4 != nil {
873                 ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.BridgeConfig.DefaultGatewayIPv4.String()
874         }
875
876         var deferIPv6Alloc bool
877         if config.BridgeConfig.FixedCIDRv6 != "" {
878                 _, fCIDRv6, err := net.ParseCIDR(config.BridgeConfig.FixedCIDRv6)
879                 if err != nil {
880                         return err
881                 }
882
883                 // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has
884                 // at least 48 host bits, we need to guarantee the current behavior where the containers'
885                 // IPv6 addresses will be constructed based on the containers' interface MAC address.
886                 // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints
887                 // on this network until after the driver has created the endpoint and returned the
888                 // constructed address. Libnetwork will then reserve this address with the ipam driver.
889                 ones, _ := fCIDRv6.Mask.Size()
890                 deferIPv6Alloc = ones <= 80
891
892                 if ipamV6Conf == nil {
893                         ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
894                 }
895                 ipamV6Conf.PreferredPool = fCIDRv6.String()
896
897                 // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6
898                 // address belongs to the same network, we need to inform libnetwork about it, so
899                 // that it can be reserved with IPAM and it will not be given away to somebody else
900                 for _, nw6 := range nw6List {
901                         if fCIDRv6.Contains(nw6.IP) {
902                                 ipamV6Conf.Gateway = nw6.IP.String()
903                                 break
904                         }
905                 }
906         }
907
908         if config.BridgeConfig.DefaultGatewayIPv6 != nil {
909                 if ipamV6Conf == nil {
910                         ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
911                 }
912                 ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.BridgeConfig.DefaultGatewayIPv6.String()
913         }
914
915         v4Conf := []*libnetwork.IpamConf{ipamV4Conf}
916         v6Conf := []*libnetwork.IpamConf{}
917         if ipamV6Conf != nil {
918                 v6Conf = append(v6Conf, ipamV6Conf)
919         }
920         // Initialize default network on "bridge" with the same name
921         _, err = controller.NewNetwork("bridge", "bridge", "",
922                 libnetwork.NetworkOptionEnableIPv6(config.BridgeConfig.EnableIPv6),
923                 libnetwork.NetworkOptionDriverOpts(netOption),
924                 libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
925                 libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))
926         if err != nil {
927                 return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
928         }
929         return nil
930 }
931
932 // Remove default bridge interface if present (--bridge=none use case)
933 func removeDefaultBridgeInterface() {
934         if lnk, err := netlink.LinkByName(bridge.DefaultBridgeName); err == nil {
935                 if err := netlink.LinkDel(lnk); err != nil {
936                         logrus.Warnf("Failed to remove bridge interface (%s): %v", bridge.DefaultBridgeName, err)
937                 }
938         }
939 }
940
941 func (daemon *Daemon) getLayerInit() func(string) error {
942         return daemon.setupInitLayer
943 }
944
945 // Parse the remapped root (user namespace) option, which can be one of:
946 //   username            - valid username from /etc/passwd
947 //   username:groupname  - valid username; valid groupname from /etc/group
948 //   uid                 - 32-bit unsigned int valid Linux UID value
949 //   uid:gid             - uid value; 32-bit unsigned int Linux GID value
950 //
951 //  If no groupname is specified, and a username is specified, an attempt
952 //  will be made to lookup a gid for that username as a groupname
953 //
954 //  If names are used, they are verified to exist in passwd/group
955 func parseRemappedRoot(usergrp string) (string, string, error) {
956
957         var (
958                 userID, groupID     int
959                 username, groupname string
960         )
961
962         idparts := strings.Split(usergrp, ":")
963         if len(idparts) > 2 {
964                 return "", "", fmt.Errorf("Invalid user/group specification in --userns-remap: %q", usergrp)
965         }
966
967         if uid, err := strconv.ParseInt(idparts[0], 10, 32); err == nil {
968                 // must be a uid; take it as valid
969                 userID = int(uid)
970                 luser, err := idtools.LookupUID(userID)
971                 if err != nil {
972                         return "", "", fmt.Errorf("Uid %d has no entry in /etc/passwd: %v", userID, err)
973                 }
974                 username = luser.Name
975                 if len(idparts) == 1 {
976                         // if the uid was numeric and no gid was specified, take the uid as the gid
977                         groupID = userID
978                         lgrp, err := idtools.LookupGID(groupID)
979                         if err != nil {
980                                 return "", "", fmt.Errorf("Gid %d has no entry in /etc/group: %v", groupID, err)
981                         }
982                         groupname = lgrp.Name
983                 }
984         } else {
985                 lookupName := idparts[0]
986                 // special case: if the user specified "default", they want Docker to create or
987                 // use (after creation) the "dockremap" user/group for root remapping
988                 if lookupName == defaultIDSpecifier {
989                         lookupName = defaultRemappedID
990                 }
991                 luser, err := idtools.LookupUser(lookupName)
992                 if err != nil && idparts[0] != defaultIDSpecifier {
993                         // error if the name requested isn't the special "dockremap" ID
994                         return "", "", fmt.Errorf("Error during uid lookup for %q: %v", lookupName, err)
995                 } else if err != nil {
996                         // special case-- if the username == "default", then we have been asked
997                         // to create a new entry pair in /etc/{passwd,group} for which the /etc/sub{uid,gid}
998                         // ranges will be used for the user and group mappings in user namespaced containers
999                         _, _, err := idtools.AddNamespaceRangesUser(defaultRemappedID)
1000                         if err == nil {
1001                                 return defaultRemappedID, defaultRemappedID, nil
1002                         }
1003                         return "", "", fmt.Errorf("Error during %q user creation: %v", defaultRemappedID, err)
1004                 }
1005                 username = luser.Name
1006                 if len(idparts) == 1 {
1007                         // we only have a string username, and no group specified; look up gid from username as group
1008                         group, err := idtools.LookupGroup(lookupName)
1009                         if err != nil {
1010                                 return "", "", fmt.Errorf("Error during gid lookup for %q: %v", lookupName, err)
1011                         }
1012                         groupname = group.Name
1013                 }
1014         }
1015
1016         if len(idparts) == 2 {
1017                 // groupname or gid is separately specified and must be resolved
1018                 // to an unsigned 32-bit gid
1019                 if gid, err := strconv.ParseInt(idparts[1], 10, 32); err == nil {
1020                         // must be a gid, take it as valid
1021                         groupID = int(gid)
1022                         lgrp, err := idtools.LookupGID(groupID)
1023                         if err != nil {
1024                                 return "", "", fmt.Errorf("Gid %d has no entry in /etc/passwd: %v", groupID, err)
1025                         }
1026                         groupname = lgrp.Name
1027                 } else {
1028                         // not a number; attempt a lookup
1029                         if _, err := idtools.LookupGroup(idparts[1]); err != nil {
1030                                 return "", "", fmt.Errorf("Error during groupname lookup for %q: %v", idparts[1], err)
1031                         }
1032                         groupname = idparts[1]
1033                 }
1034         }
1035         return username, groupname, nil
1036 }
1037
1038 func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
1039         if runtime.GOOS != "linux" && config.RemappedRoot != "" {
1040                 return nil, fmt.Errorf("User namespaces are only supported on Linux")
1041         }
1042
1043         // if the daemon was started with remapped root option, parse
1044         // the config option to the int uid,gid values
1045         if config.RemappedRoot != "" {
1046                 username, groupname, err := parseRemappedRoot(config.RemappedRoot)
1047                 if err != nil {
1048                         return nil, err
1049                 }
1050                 if username == "root" {
1051                         // Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
1052                         // effectively
1053                         logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
1054                         return &idtools.IDMappings{}, nil
1055                 }
1056                 logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
1057                 // update remapped root setting now that we have resolved them to actual names
1058                 config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
1059
1060                 mappings, err := idtools.NewIDMappings(username, groupname)
1061                 if err != nil {
1062                         return nil, errors.Wrapf(err, "Can't create ID mappings: %v")
1063                 }
1064                 return mappings, nil
1065         }
1066         return &idtools.IDMappings{}, nil
1067 }
1068
1069 func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
1070         config.Root = rootDir
1071         // the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
1072         // so that syscalls executing as non-root, operating on subdirectories of the graph root
1073         // (e.g. mounted layers of a container) can traverse this path.
1074         // The user namespace support will create subdirectories for the remapped root host uid:gid
1075         // pair owned by that same uid:gid pair for proper write access to those needed metadata and
1076         // layer content subtrees.
1077         if _, err := os.Stat(rootDir); err == nil {
1078                 // root current exists; verify the access bits are correct by setting them
1079                 if err = os.Chmod(rootDir, 0711); err != nil {
1080                         return err
1081                 }
1082         } else if os.IsNotExist(err) {
1083                 // no root exists yet, create it 0711 with root:root ownership
1084                 if err := os.MkdirAll(rootDir, 0711); err != nil {
1085                         return err
1086                 }
1087         }
1088
1089         // if user namespaces are enabled we will create a subtree underneath the specified root
1090         // with any/all specified remapped root uid/gid options on the daemon creating
1091         // a new subdirectory with ownership set to the remapped uid/gid (so as to allow
1092         // `chdir()` to work for containers namespaced to that uid/gid)
1093         if config.RemappedRoot != "" {
1094                 config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID))
1095                 logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
1096                 // Create the root directory if it doesn't exist
1097                 if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil {
1098                         return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
1099                 }
1100                 // we also need to verify that any pre-existing directories in the path to
1101                 // the graphroot won't block access to remapped root--if any pre-existing directory
1102                 // has strict permissions that don't allow "x", container start will fail, so
1103                 // better to warn and fail now
1104                 dirPath := config.Root
1105                 for {
1106                         dirPath = filepath.Dir(dirPath)
1107                         if dirPath == "/" {
1108                                 break
1109                         }
1110                         if !idtools.CanAccess(dirPath, rootIDs) {
1111                                 return fmt.Errorf("A subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories.", config.Root)
1112                         }
1113                 }
1114         }
1115         return nil
1116 }
1117
1118 // registerLinks writes the links to a file.
1119 func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
1120         if hostConfig == nil || hostConfig.NetworkMode.IsUserDefined() {
1121                 return nil
1122         }
1123
1124         for _, l := range hostConfig.Links {
1125                 name, alias, err := opts.ParseLink(l)
1126                 if err != nil {
1127                         return err
1128                 }
1129                 child, err := daemon.GetContainer(name)
1130                 if err != nil {
1131                         return fmt.Errorf("Could not get container for %s", name)
1132                 }
1133                 for child.HostConfig.NetworkMode.IsContainer() {
1134                         parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
1135                         child, err = daemon.GetContainer(parts[1])
1136                         if err != nil {
1137                                 return fmt.Errorf("Could not get container for %s", parts[1])
1138                         }
1139                 }
1140                 if child.HostConfig.NetworkMode.IsHost() {
1141                         return runconfig.ErrConflictHostNetworkAndLinks
1142                 }
1143                 if err := daemon.registerLink(container, child, alias); err != nil {
1144                         return err
1145                 }
1146         }
1147
1148         // After we load all the links into the daemon
1149         // set them to nil on the hostconfig
1150         _, err := container.WriteHostConfig()
1151         return err
1152 }
1153
1154 // conditionalMountOnStart is a platform specific helper function during the
1155 // container start to call mount.
1156 func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
1157         return daemon.Mount(container)
1158 }
1159
1160 // conditionalUnmountOnCleanup is a platform specific helper function called
1161 // during the cleanup of a container to unmount.
1162 func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
1163         return daemon.Unmount(container)
1164 }
1165
1166 func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
1167         if !c.IsRunning() {
1168                 return nil, errNotRunning{c.ID}
1169         }
1170         stats, err := daemon.containerd.Stats(c.ID)
1171         if err != nil {
1172                 return nil, err
1173         }
1174         s := &types.StatsJSON{}
1175         cgs := stats.CgroupStats
1176         if cgs != nil {
1177                 s.BlkioStats = types.BlkioStats{
1178                         IoServiceBytesRecursive: copyBlkioEntry(cgs.BlkioStats.IoServiceBytesRecursive),
1179                         IoServicedRecursive:     copyBlkioEntry(cgs.BlkioStats.IoServicedRecursive),
1180                         IoQueuedRecursive:       copyBlkioEntry(cgs.BlkioStats.IoQueuedRecursive),
1181                         IoServiceTimeRecursive:  copyBlkioEntry(cgs.BlkioStats.IoServiceTimeRecursive),
1182                         IoWaitTimeRecursive:     copyBlkioEntry(cgs.BlkioStats.IoWaitTimeRecursive),
1183                         IoMergedRecursive:       copyBlkioEntry(cgs.BlkioStats.IoMergedRecursive),
1184                         IoTimeRecursive:         copyBlkioEntry(cgs.BlkioStats.IoTimeRecursive),
1185                         SectorsRecursive:        copyBlkioEntry(cgs.BlkioStats.SectorsRecursive),
1186                 }
1187                 cpu := cgs.CpuStats
1188                 s.CPUStats = types.CPUStats{
1189                         CPUUsage: types.CPUUsage{
1190                                 TotalUsage:        cpu.CpuUsage.TotalUsage,
1191                                 PercpuUsage:       cpu.CpuUsage.PercpuUsage,
1192                                 UsageInKernelmode: cpu.CpuUsage.UsageInKernelmode,
1193                                 UsageInUsermode:   cpu.CpuUsage.UsageInUsermode,
1194                         },
1195                         ThrottlingData: types.ThrottlingData{
1196                                 Periods:          cpu.ThrottlingData.Periods,
1197                                 ThrottledPeriods: cpu.ThrottlingData.ThrottledPeriods,
1198                                 ThrottledTime:    cpu.ThrottlingData.ThrottledTime,
1199                         },
1200                 }
1201                 mem := cgs.MemoryStats.Usage
1202                 s.MemoryStats = types.MemoryStats{
1203                         Usage:    mem.Usage,
1204                         MaxUsage: mem.MaxUsage,
1205                         Stats:    cgs.MemoryStats.Stats,
1206                         Failcnt:  mem.Failcnt,
1207                         Limit:    mem.Limit,
1208                 }
1209                 // if the container does not set memory limit, use the machineMemory
1210                 if mem.Limit > daemon.machineMemory && daemon.machineMemory > 0 {
1211                         s.MemoryStats.Limit = daemon.machineMemory
1212                 }
1213                 if cgs.PidsStats != nil {
1214                         s.PidsStats = types.PidsStats{
1215                                 Current: cgs.PidsStats.Current,
1216                         }
1217                 }
1218         }
1219         s.Read, err = ptypes.Timestamp(stats.Timestamp)
1220         if err != nil {
1221                 return nil, err
1222         }
1223         return s, nil
1224 }
1225
1226 // setDefaultIsolation determines the default isolation mode for the
1227 // daemon to run in. This is only applicable on Windows
1228 func (daemon *Daemon) setDefaultIsolation() error {
1229         return nil
1230 }
1231
1232 func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
1233         var layers []string
1234         for _, l := range rootfs.DiffIDs {
1235                 layers = append(layers, l.String())
1236         }
1237         return types.RootFS{
1238                 Type:   rootfs.Type,
1239                 Layers: layers,
1240         }
1241 }
1242
1243 // setupDaemonProcess sets various settings for the daemon's process
1244 func setupDaemonProcess(config *config.Config) error {
1245         // setup the daemons oom_score_adj
1246         return setupOOMScoreAdj(config.OOMScoreAdjust)
1247 }
1248
1249 func setupOOMScoreAdj(score int) error {
1250         f, err := os.OpenFile("/proc/self/oom_score_adj", os.O_WRONLY, 0)
1251         if err != nil {
1252                 return err
1253         }
1254         defer f.Close()
1255         stringScore := strconv.Itoa(score)
1256         _, err = f.WriteString(stringScore)
1257         if os.IsPermission(err) {
1258                 // Setting oom_score_adj does not work in an
1259                 // unprivileged container. Ignore the error, but log
1260                 // it if we appear not to be in that situation.
1261                 if !rsystem.RunningInUserNS() {
1262                         logrus.Debugf("Permission denied writing %q to /proc/self/oom_score_adj", stringScore)
1263                 }
1264                 return nil
1265         }
1266
1267         return err
1268 }
1269
1270 func (daemon *Daemon) initCgroupsPath(path string) error {
1271         if path == "/" || path == "." {
1272                 return nil
1273         }
1274
1275         if daemon.configStore.CPURealtimePeriod == 0 && daemon.configStore.CPURealtimeRuntime == 0 {
1276                 return nil
1277         }
1278
1279         // Recursively create cgroup to ensure that the system and all parent cgroups have values set
1280         // for the period and runtime as this limits what the children can be set to.
1281         daemon.initCgroupsPath(filepath.Dir(path))
1282
1283         mnt, root, err := cgroups.FindCgroupMountpointAndRoot("cpu")
1284         if err != nil {
1285                 return err
1286         }
1287         // When docker is run inside docker, the root is based of the host cgroup.
1288         // Should this be handled in runc/libcontainer/cgroups ?
1289         if strings.HasPrefix(root, "/docker/") {
1290                 root = "/"
1291         }
1292
1293         path = filepath.Join(mnt, root, path)
1294         sysinfo := sysinfo.New(true)
1295         if err := maybeCreateCPURealTimeFile(sysinfo.CPURealtimePeriod, daemon.configStore.CPURealtimePeriod, "cpu.rt_period_us", path); err != nil {
1296                 return err
1297         }
1298         if err := maybeCreateCPURealTimeFile(sysinfo.CPURealtimeRuntime, daemon.configStore.CPURealtimeRuntime, "cpu.rt_runtime_us", path); err != nil {
1299                 return err
1300         }
1301         return nil
1302 }
1303
1304 func maybeCreateCPURealTimeFile(sysinfoPresent bool, configValue int64, file string, path string) error {
1305         if sysinfoPresent && configValue != 0 {
1306                 if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
1307                         return err
1308                 }
1309                 if err := ioutil.WriteFile(filepath.Join(path, file), []byte(strconv.FormatInt(configValue, 10)), 0700); err != nil {
1310                         return err
1311                 }
1312         }
1313         return nil
1314 }
1315
1316 func (daemon *Daemon) setupSeccompProfile() error {
1317         if daemon.configStore.SeccompProfile != "" {
1318                 daemon.seccompProfilePath = daemon.configStore.SeccompProfile
1319                 b, err := ioutil.ReadFile(daemon.configStore.SeccompProfile)
1320                 if err != nil {
1321                         return fmt.Errorf("opening seccomp profile (%s) failed: %v", daemon.configStore.SeccompProfile, err)
1322                 }
1323                 daemon.seccompProfile = b
1324         }
1325         return nil
1326 }