gopkg.in/dotcloud/docker.v1@v1.13.1/daemon/oci_linux.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"sort"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/Sirupsen/logrus"
    14  	containertypes "github.com/docker/docker/api/types/container"
    15  	"github.com/docker/docker/container"
    16  	"github.com/docker/docker/daemon/caps"
    17  	"github.com/docker/docker/oci"
    18  	"github.com/docker/docker/pkg/idtools"
    19  	"github.com/docker/docker/pkg/mount"
    20  	"github.com/docker/docker/pkg/stringutils"
    21  	"github.com/docker/docker/pkg/symlink"
    22  	"github.com/docker/docker/volume"
    23  	"github.com/opencontainers/runc/libcontainer/apparmor"
    24  	"github.com/opencontainers/runc/libcontainer/cgroups"
    25  	"github.com/opencontainers/runc/libcontainer/devices"
    26  	"github.com/opencontainers/runc/libcontainer/user"
    27  	specs "github.com/opencontainers/runtime-spec/specs-go"
    28  )
    29  
    30  func setResources(s *specs.Spec, r containertypes.Resources) error {
    31  	weightDevices, err := getBlkioWeightDevices(r)
    32  	if err != nil {
    33  		return err
    34  	}
    35  	readBpsDevice, err := getBlkioThrottleDevices(r.BlkioDeviceReadBps)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	writeBpsDevice, err := getBlkioThrottleDevices(r.BlkioDeviceWriteBps)
    40  	if err != nil {
    41  		return err
    42  	}
    43  	readIOpsDevice, err := getBlkioThrottleDevices(r.BlkioDeviceReadIOps)
    44  	if err != nil {
    45  		return err
    46  	}
    47  	writeIOpsDevice, err := getBlkioThrottleDevices(r.BlkioDeviceWriteIOps)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	memoryRes := getMemoryResources(r)
    53  	cpuRes := getCPUResources(r)
    54  	blkioWeight := r.BlkioWeight
    55  
    56  	specResources := &specs.Resources{
    57  		Memory: memoryRes,
    58  		CPU:    cpuRes,
    59  		BlockIO: &specs.BlockIO{
    60  			Weight:                  &blkioWeight,
    61  			WeightDevice:            weightDevices,
    62  			ThrottleReadBpsDevice:   readBpsDevice,
    63  			ThrottleWriteBpsDevice:  writeBpsDevice,
    64  			ThrottleReadIOPSDevice:  readIOpsDevice,
    65  			ThrottleWriteIOPSDevice: writeIOpsDevice,
    66  		},
    67  		DisableOOMKiller: r.OomKillDisable,
    68  		Pids: &specs.Pids{
    69  			Limit: &r.PidsLimit,
    70  		},
    71  	}
    72  
    73  	if s.Linux.Resources != nil && len(s.Linux.Resources.Devices) > 0 {
    74  		specResources.Devices = s.Linux.Resources.Devices
    75  	}
    76  
    77  	s.Linux.Resources = specResources
    78  	return nil
    79  }
    80  
    81  func setDevices(s *specs.Spec, c *container.Container) error {
    82  	// Build lists of devices allowed and created within the container.
    83  	var devs []specs.Device
    84  	devPermissions := s.Linux.Resources.Devices
    85  	if c.HostConfig.Privileged {
    86  		hostDevices, err := devices.HostDevices()
    87  		if err != nil {
    88  			return err
    89  		}
    90  		for _, d := range hostDevices {
    91  			devs = append(devs, oci.Device(d))
    92  		}
    93  		rwm := "rwm"
    94  		devPermissions = []specs.DeviceCgroup{
    95  			{
    96  				Allow:  true,
    97  				Access: &rwm,
    98  			},
    99  		}
   100  	} else {
   101  		for _, deviceMapping := range c.HostConfig.Devices {
   102  			d, dPermissions, err := oci.DevicesFromPath(deviceMapping.PathOnHost, deviceMapping.PathInContainer, deviceMapping.CgroupPermissions)
   103  			if err != nil {
   104  				return err
   105  			}
   106  			devs = append(devs, d...)
   107  			devPermissions = append(devPermissions, dPermissions...)
   108  		}
   109  	}
   110  
   111  	s.Linux.Devices = append(s.Linux.Devices, devs...)
   112  	s.Linux.Resources.Devices = devPermissions
   113  	return nil
   114  }
   115  
   116  func setRlimits(daemon *Daemon, s *specs.Spec, c *container.Container) error {
   117  	var rlimits []specs.Rlimit
   118  
   119  	// We want to leave the original HostConfig alone so make a copy here
   120  	hostConfig := *c.HostConfig
   121  	// Merge with the daemon defaults
   122  	daemon.mergeUlimits(&hostConfig)
   123  	for _, ul := range hostConfig.Ulimits {
   124  		rlimits = append(rlimits, specs.Rlimit{
   125  			Type: "RLIMIT_" + strings.ToUpper(ul.Name),
   126  			Soft: uint64(ul.Soft),
   127  			Hard: uint64(ul.Hard),
   128  		})
   129  	}
   130  
   131  	s.Process.Rlimits = rlimits
   132  	return nil
   133  }
   134  
   135  func setUser(s *specs.Spec, c *container.Container) error {
   136  	uid, gid, additionalGids, err := getUser(c, c.Config.User)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	s.Process.User.UID = uid
   141  	s.Process.User.GID = gid
   142  	s.Process.User.AdditionalGids = additionalGids
   143  	return nil
   144  }
   145  
   146  func readUserFile(c *container.Container, p string) (io.ReadCloser, error) {
   147  	fp, err := symlink.FollowSymlinkInScope(filepath.Join(c.BaseFS, p), c.BaseFS)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	return os.Open(fp)
   152  }
   153  
   154  func getUser(c *container.Container, username string) (uint32, uint32, []uint32, error) {
   155  	passwdPath, err := user.GetPasswdPath()
   156  	if err != nil {
   157  		return 0, 0, nil, err
   158  	}
   159  	groupPath, err := user.GetGroupPath()
   160  	if err != nil {
   161  		return 0, 0, nil, err
   162  	}
   163  	passwdFile, err := readUserFile(c, passwdPath)
   164  	if err == nil {
   165  		defer passwdFile.Close()
   166  	}
   167  	groupFile, err := readUserFile(c, groupPath)
   168  	if err == nil {
   169  		defer groupFile.Close()
   170  	}
   171  
   172  	execUser, err := user.GetExecUser(username, nil, passwdFile, groupFile)
   173  	if err != nil {
   174  		return 0, 0, nil, err
   175  	}
   176  
   177  	// todo: fix this double read by a change to libcontainer/user pkg
   178  	groupFile, err = readUserFile(c, groupPath)
   179  	if err == nil {
   180  		defer groupFile.Close()
   181  	}
   182  	var addGroups []int
   183  	if len(c.HostConfig.GroupAdd) > 0 {
   184  		addGroups, err = user.GetAdditionalGroups(c.HostConfig.GroupAdd, groupFile)
   185  		if err != nil {
   186  			return 0, 0, nil, err
   187  		}
   188  	}
   189  	uid := uint32(execUser.Uid)
   190  	gid := uint32(execUser.Gid)
   191  	sgids := append(execUser.Sgids, addGroups...)
   192  	var additionalGids []uint32
   193  	for _, g := range sgids {
   194  		additionalGids = append(additionalGids, uint32(g))
   195  	}
   196  	return uid, gid, additionalGids, nil
   197  }
   198  
   199  func setNamespace(s *specs.Spec, ns specs.Namespace) {
   200  	for i, n := range s.Linux.Namespaces {
   201  		if n.Type == ns.Type {
   202  			s.Linux.Namespaces[i] = ns
   203  			return
   204  		}
   205  	}
   206  	s.Linux.Namespaces = append(s.Linux.Namespaces, ns)
   207  }
   208  
   209  func setCapabilities(s *specs.Spec, c *container.Container) error {
   210  	var caplist []string
   211  	var err error
   212  	if c.HostConfig.Privileged {
   213  		caplist = caps.GetAllCapabilities()
   214  	} else {
   215  		caplist, err = caps.TweakCapabilities(s.Process.Capabilities, c.HostConfig.CapAdd, c.HostConfig.CapDrop)
   216  		if err != nil {
   217  			return err
   218  		}
   219  	}
   220  	s.Process.Capabilities = caplist
   221  	return nil
   222  }
   223  
   224  func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error {
   225  	userNS := false
   226  	// user
   227  	if c.HostConfig.UsernsMode.IsPrivate() {
   228  		uidMap, gidMap := daemon.GetUIDGIDMaps()
   229  		if uidMap != nil {
   230  			userNS = true
   231  			ns := specs.Namespace{Type: "user"}
   232  			setNamespace(s, ns)
   233  			s.Linux.UIDMappings = specMapping(uidMap)
   234  			s.Linux.GIDMappings = specMapping(gidMap)
   235  		}
   236  	}
   237  	// network
   238  	if !c.Config.NetworkDisabled {
   239  		ns := specs.Namespace{Type: "network"}
   240  		parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2)
   241  		if parts[0] == "container" {
   242  			nc, err := daemon.getNetworkedContainer(c.ID, c.HostConfig.NetworkMode.ConnectedContainer())
   243  			if err != nil {
   244  				return err
   245  			}
   246  			ns.Path = fmt.Sprintf("/proc/%d/ns/net", nc.State.GetPID())
   247  			if userNS {
   248  				// to share a net namespace, they must also share a user namespace
   249  				nsUser := specs.Namespace{Type: "user"}
   250  				nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", nc.State.GetPID())
   251  				setNamespace(s, nsUser)
   252  			}
   253  		} else if c.HostConfig.NetworkMode.IsHost() {
   254  			ns.Path = c.NetworkSettings.SandboxKey
   255  		}
   256  		setNamespace(s, ns)
   257  	}
   258  	// ipc
   259  	if c.HostConfig.IpcMode.IsContainer() {
   260  		ns := specs.Namespace{Type: "ipc"}
   261  		ic, err := daemon.getIpcContainer(c)
   262  		if err != nil {
   263  			return err
   264  		}
   265  		ns.Path = fmt.Sprintf("/proc/%d/ns/ipc", ic.State.GetPID())
   266  		setNamespace(s, ns)
   267  		if userNS {
   268  			// to share an IPC namespace, they must also share a user namespace
   269  			nsUser := specs.Namespace{Type: "user"}
   270  			nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", ic.State.GetPID())
   271  			setNamespace(s, nsUser)
   272  		}
   273  	} else if c.HostConfig.IpcMode.IsHost() {
   274  		oci.RemoveNamespace(s, specs.NamespaceType("ipc"))
   275  	} else {
   276  		ns := specs.Namespace{Type: "ipc"}
   277  		setNamespace(s, ns)
   278  	}
   279  	// pid
   280  	if c.HostConfig.PidMode.IsContainer() {
   281  		ns := specs.Namespace{Type: "pid"}
   282  		pc, err := daemon.getPidContainer(c)
   283  		if err != nil {
   284  			return err
   285  		}
   286  		ns.Path = fmt.Sprintf("/proc/%d/ns/pid", pc.State.GetPID())
   287  		setNamespace(s, ns)
   288  		if userNS {
   289  			// to share a PID namespace, they must also share a user namespace
   290  			nsUser := specs.Namespace{Type: "user"}
   291  			nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", pc.State.GetPID())
   292  			setNamespace(s, nsUser)
   293  		}
   294  	} else if c.HostConfig.PidMode.IsHost() {
   295  		oci.RemoveNamespace(s, specs.NamespaceType("pid"))
   296  	} else {
   297  		ns := specs.Namespace{Type: "pid"}
   298  		setNamespace(s, ns)
   299  	}
   300  	// uts
   301  	if c.HostConfig.UTSMode.IsHost() {
   302  		oci.RemoveNamespace(s, specs.NamespaceType("uts"))
   303  		s.Hostname = ""
   304  	}
   305  
   306  	return nil
   307  }
   308  
   309  func specMapping(s []idtools.IDMap) []specs.IDMapping {
   310  	var ids []specs.IDMapping
   311  	for _, item := range s {
   312  		ids = append(ids, specs.IDMapping{
   313  			HostID:      uint32(item.HostID),
   314  			ContainerID: uint32(item.ContainerID),
   315  			Size:        uint32(item.Size),
   316  		})
   317  	}
   318  	return ids
   319  }
   320  
   321  func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info {
   322  	for _, m := range mountinfo {
   323  		if m.Mountpoint == dir {
   324  			return m
   325  		}
   326  	}
   327  	return nil
   328  }
   329  
   330  // Get the source mount point of directory passed in as argument. Also return
   331  // optional fields.
   332  func getSourceMount(source string) (string, string, error) {
   333  	// Ensure any symlinks are resolved.
   334  	sourcePath, err := filepath.EvalSymlinks(source)
   335  	if err != nil {
   336  		return "", "", err
   337  	}
   338  
   339  	mountinfos, err := mount.GetMounts()
   340  	if err != nil {
   341  		return "", "", err
   342  	}
   343  
   344  	mountinfo := getMountInfo(mountinfos, sourcePath)
   345  	if mountinfo != nil {
   346  		return sourcePath, mountinfo.Optional, nil
   347  	}
   348  
   349  	path := sourcePath
   350  	for {
   351  		path = filepath.Dir(path)
   352  
   353  		mountinfo = getMountInfo(mountinfos, path)
   354  		if mountinfo != nil {
   355  			return path, mountinfo.Optional, nil
   356  		}
   357  
   358  		if path == "/" {
   359  			break
   360  		}
   361  	}
   362  
   363  	// If we are here, we did not find parent mount. Something is wrong.
   364  	return "", "", fmt.Errorf("Could not find source mount of %s", source)
   365  }
   366  
   367  // Ensure mount point on which path is mounted, is shared.
   368  func ensureShared(path string) error {
   369  	sharedMount := false
   370  
   371  	sourceMount, optionalOpts, err := getSourceMount(path)
   372  	if err != nil {
   373  		return err
   374  	}
   375  	// Make sure source mount point is shared.
   376  	optsSplit := strings.Split(optionalOpts, " ")
   377  	for _, opt := range optsSplit {
   378  		if strings.HasPrefix(opt, "shared:") {
   379  			sharedMount = true
   380  			break
   381  		}
   382  	}
   383  
   384  	if !sharedMount {
   385  		return fmt.Errorf("Path %s is mounted on %s but it is not a shared mount.", path, sourceMount)
   386  	}
   387  	return nil
   388  }
   389  
   390  // Ensure mount point on which path is mounted, is either shared or slave.
   391  func ensureSharedOrSlave(path string) error {
   392  	sharedMount := false
   393  	slaveMount := false
   394  
   395  	sourceMount, optionalOpts, err := getSourceMount(path)
   396  	if err != nil {
   397  		return err
   398  	}
   399  	// Make sure source mount point is shared.
   400  	optsSplit := strings.Split(optionalOpts, " ")
   401  	for _, opt := range optsSplit {
   402  		if strings.HasPrefix(opt, "shared:") {
   403  			sharedMount = true
   404  			break
   405  		} else if strings.HasPrefix(opt, "master:") {
   406  			slaveMount = true
   407  			break
   408  		}
   409  	}
   410  
   411  	if !sharedMount && !slaveMount {
   412  		return fmt.Errorf("Path %s is mounted on %s but it is not a shared or slave mount.", path, sourceMount)
   413  	}
   414  	return nil
   415  }
   416  
   417  var (
   418  	mountPropagationMap = map[string]int{
   419  		"private":  mount.PRIVATE,
   420  		"rprivate": mount.RPRIVATE,
   421  		"shared":   mount.SHARED,
   422  		"rshared":  mount.RSHARED,
   423  		"slave":    mount.SLAVE,
   424  		"rslave":   mount.RSLAVE,
   425  	}
   426  
   427  	mountPropagationReverseMap = map[int]string{
   428  		mount.PRIVATE:  "private",
   429  		mount.RPRIVATE: "rprivate",
   430  		mount.SHARED:   "shared",
   431  		mount.RSHARED:  "rshared",
   432  		mount.SLAVE:    "slave",
   433  		mount.RSLAVE:   "rslave",
   434  	}
   435  )
   436  
   437  func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []container.Mount) error {
   438  	userMounts := make(map[string]struct{})
   439  	for _, m := range mounts {
   440  		userMounts[m.Destination] = struct{}{}
   441  	}
   442  
   443  	// Filter out mounts that are overridden by user supplied mounts
   444  	var defaultMounts []specs.Mount
   445  	_, mountDev := userMounts["/dev"]
   446  	for _, m := range s.Mounts {
   447  		if _, ok := userMounts[m.Destination]; !ok {
   448  			if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
   449  				continue
   450  			}
   451  			defaultMounts = append(defaultMounts, m)
   452  		}
   453  	}
   454  
   455  	s.Mounts = defaultMounts
   456  	for _, m := range mounts {
   457  		for _, cm := range s.Mounts {
   458  			if cm.Destination == m.Destination {
   459  				return fmt.Errorf("Duplicate mount point '%s'", m.Destination)
   460  			}
   461  		}
   462  
   463  		if m.Source == "tmpfs" {
   464  			data := m.Data
   465  			options := []string{"noexec", "nosuid", "nodev", string(volume.DefaultPropagationMode)}
   466  			if data != "" {
   467  				options = append(options, strings.Split(data, ",")...)
   468  			}
   469  
   470  			merged, err := mount.MergeTmpfsOptions(options)
   471  			if err != nil {
   472  				return err
   473  			}
   474  
   475  			s.Mounts = append(s.Mounts, specs.Mount{Destination: m.Destination, Source: m.Source, Type: "tmpfs", Options: merged})
   476  			continue
   477  		}
   478  
   479  		mt := specs.Mount{Destination: m.Destination, Source: m.Source, Type: "bind"}
   480  
   481  		// Determine property of RootPropagation based on volume
   482  		// properties. If a volume is shared, then keep root propagation
   483  		// shared. This should work for slave and private volumes too.
   484  		//
   485  		// For slave volumes, it can be either [r]shared/[r]slave.
   486  		//
   487  		// For private volumes any root propagation value should work.
   488  		pFlag := mountPropagationMap[m.Propagation]
   489  		if pFlag == mount.SHARED || pFlag == mount.RSHARED {
   490  			if err := ensureShared(m.Source); err != nil {
   491  				return err
   492  			}
   493  			rootpg := mountPropagationMap[s.Linux.RootfsPropagation]
   494  			if rootpg != mount.SHARED && rootpg != mount.RSHARED {
   495  				s.Linux.RootfsPropagation = mountPropagationReverseMap[mount.SHARED]
   496  			}
   497  		} else if pFlag == mount.SLAVE || pFlag == mount.RSLAVE {
   498  			if err := ensureSharedOrSlave(m.Source); err != nil {
   499  				return err
   500  			}
   501  			rootpg := mountPropagationMap[s.Linux.RootfsPropagation]
   502  			if rootpg != mount.SHARED && rootpg != mount.RSHARED && rootpg != mount.SLAVE && rootpg != mount.RSLAVE {
   503  				s.Linux.RootfsPropagation = mountPropagationReverseMap[mount.RSLAVE]
   504  			}
   505  		}
   506  
   507  		opts := []string{"rbind"}
   508  		if !m.Writable {
   509  			opts = append(opts, "ro")
   510  		}
   511  		if pFlag != 0 {
   512  			opts = append(opts, mountPropagationReverseMap[pFlag])
   513  		}
   514  
   515  		mt.Options = opts
   516  		s.Mounts = append(s.Mounts, mt)
   517  	}
   518  
   519  	if s.Root.Readonly {
   520  		for i, m := range s.Mounts {
   521  			switch m.Destination {
   522  			case "/proc", "/dev/pts", "/dev/mqueue": // /dev is remounted by runc
   523  				continue
   524  			}
   525  			if _, ok := userMounts[m.Destination]; !ok {
   526  				if !stringutils.InSlice(m.Options, "ro") {
   527  					s.Mounts[i].Options = append(s.Mounts[i].Options, "ro")
   528  				}
   529  			}
   530  		}
   531  	}
   532  
   533  	if c.HostConfig.Privileged {
   534  		if !s.Root.Readonly {
   535  			// clear readonly for /sys
   536  			for i := range s.Mounts {
   537  				if s.Mounts[i].Destination == "/sys" {
   538  					clearReadOnly(&s.Mounts[i])
   539  				}
   540  			}
   541  		}
   542  		s.Linux.ReadonlyPaths = nil
   543  		s.Linux.MaskedPaths = nil
   544  	}
   545  
   546  	// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
   547  	// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
   548  	if uidMap, _ := daemon.GetUIDGIDMaps(); uidMap != nil || c.HostConfig.Privileged {
   549  		for i, m := range s.Mounts {
   550  			if m.Type == "cgroup" {
   551  				clearReadOnly(&s.Mounts[i])
   552  			}
   553  		}
   554  	}
   555  
   556  	return nil
   557  }
   558  
   559  func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) error {
   560  	linkedEnv, err := daemon.setupLinkedContainers(c)
   561  	if err != nil {
   562  		return err
   563  	}
   564  	s.Root = specs.Root{
   565  		Path:     c.BaseFS,
   566  		Readonly: c.HostConfig.ReadonlyRootfs,
   567  	}
   568  	rootUID, rootGID := daemon.GetRemappedUIDGID()
   569  	if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil {
   570  		return err
   571  	}
   572  	cwd := c.Config.WorkingDir
   573  	if len(cwd) == 0 {
   574  		cwd = "/"
   575  	}
   576  	s.Process.Args = append([]string{c.Path}, c.Args...)
   577  
   578  	// only add the custom init if it is specified and the container is running in its
   579  	// own private pid namespace.  It does not make sense to add if it is running in the
   580  	// host namespace or another container's pid namespace where we already have an init
   581  	if c.HostConfig.PidMode.IsPrivate() {
   582  		if (c.HostConfig.Init != nil && *c.HostConfig.Init) ||
   583  			(c.HostConfig.Init == nil && daemon.configStore.Init) {
   584  			s.Process.Args = append([]string{"/dev/init", "--", c.Path}, c.Args...)
   585  			var path string
   586  			if daemon.configStore.InitPath == "" && c.HostConfig.InitPath == "" {
   587  				path, err = exec.LookPath(DefaultInitBinary)
   588  				if err != nil {
   589  					return err
   590  				}
   591  			}
   592  			if daemon.configStore.InitPath != "" {
   593  				path = daemon.configStore.InitPath
   594  			}
   595  			if c.HostConfig.InitPath != "" {
   596  				path = c.HostConfig.InitPath
   597  			}
   598  			s.Mounts = append(s.Mounts, specs.Mount{
   599  				Destination: "/dev/init",
   600  				Type:        "bind",
   601  				Source:      path,
   602  				Options:     []string{"bind", "ro"},
   603  			})
   604  		}
   605  	}
   606  	s.Process.Cwd = cwd
   607  	s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
   608  	s.Process.Terminal = c.Config.Tty
   609  	s.Hostname = c.FullHostname()
   610  
   611  	return nil
   612  }
   613  
   614  func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
   615  	s := oci.DefaultSpec()
   616  	if err := daemon.populateCommonSpec(&s, c); err != nil {
   617  		return nil, err
   618  	}
   619  
   620  	var cgroupsPath string
   621  	scopePrefix := "docker"
   622  	parent := "/docker"
   623  	useSystemd := UsingSystemd(daemon.configStore)
   624  	if useSystemd {
   625  		parent = "system.slice"
   626  	}
   627  
   628  	if c.HostConfig.CgroupParent != "" {
   629  		parent = c.HostConfig.CgroupParent
   630  	} else if daemon.configStore.CgroupParent != "" {
   631  		parent = daemon.configStore.CgroupParent
   632  	}
   633  
   634  	if useSystemd {
   635  		cgroupsPath = parent + ":" + scopePrefix + ":" + c.ID
   636  		logrus.Debugf("createSpec: cgroupsPath: %s", cgroupsPath)
   637  	} else {
   638  		cgroupsPath = filepath.Join(parent, c.ID)
   639  	}
   640  	s.Linux.CgroupsPath = &cgroupsPath
   641  
   642  	if err := setResources(&s, c.HostConfig.Resources); err != nil {
   643  		return nil, fmt.Errorf("linux runtime spec resources: %v", err)
   644  	}
   645  	s.Linux.Resources.OOMScoreAdj = &c.HostConfig.OomScoreAdj
   646  	s.Linux.Sysctl = c.HostConfig.Sysctls
   647  
   648  	p := *s.Linux.CgroupsPath
   649  	if useSystemd {
   650  		initPath, err := cgroups.GetInitCgroupDir("cpu")
   651  		if err != nil {
   652  			return nil, err
   653  		}
   654  		p, _ = cgroups.GetThisCgroupDir("cpu")
   655  		if err != nil {
   656  			return nil, err
   657  		}
   658  		p = filepath.Join(initPath, p)
   659  	}
   660  
   661  	// Clean path to guard against things like ../../../BAD
   662  	parentPath := filepath.Dir(p)
   663  	if !filepath.IsAbs(parentPath) {
   664  		parentPath = filepath.Clean("/" + parentPath)
   665  	}
   666  
   667  	if err := daemon.initCgroupsPath(parentPath); err != nil {
   668  		return nil, fmt.Errorf("linux init cgroups path: %v", err)
   669  	}
   670  	if err := setDevices(&s, c); err != nil {
   671  		return nil, fmt.Errorf("linux runtime spec devices: %v", err)
   672  	}
   673  	if err := setRlimits(daemon, &s, c); err != nil {
   674  		return nil, fmt.Errorf("linux runtime spec rlimits: %v", err)
   675  	}
   676  	if err := setUser(&s, c); err != nil {
   677  		return nil, fmt.Errorf("linux spec user: %v", err)
   678  	}
   679  	if err := setNamespaces(daemon, &s, c); err != nil {
   680  		return nil, fmt.Errorf("linux spec namespaces: %v", err)
   681  	}
   682  	if err := setCapabilities(&s, c); err != nil {
   683  		return nil, fmt.Errorf("linux spec capabilities: %v", err)
   684  	}
   685  	if err := setSeccomp(daemon, &s, c); err != nil {
   686  		return nil, fmt.Errorf("linux seccomp: %v", err)
   687  	}
   688  
   689  	if err := daemon.setupIpcDirs(c); err != nil {
   690  		return nil, err
   691  	}
   692  
   693  	if err := daemon.setupSecretDir(c); err != nil {
   694  		return nil, err
   695  	}
   696  
   697  	ms, err := daemon.setupMounts(c)
   698  	if err != nil {
   699  		return nil, err
   700  	}
   701  
   702  	ms = append(ms, c.IpcMounts()...)
   703  
   704  	tmpfsMounts, err := c.TmpfsMounts()
   705  	if err != nil {
   706  		return nil, err
   707  	}
   708  	ms = append(ms, tmpfsMounts...)
   709  
   710  	if m := c.SecretMount(); m != nil {
   711  		ms = append(ms, *m)
   712  	}
   713  
   714  	sort.Sort(mounts(ms))
   715  	if err := setMounts(daemon, &s, c, ms); err != nil {
   716  		return nil, fmt.Errorf("linux mounts: %v", err)
   717  	}
   718  
   719  	for _, ns := range s.Linux.Namespaces {
   720  		if ns.Type == "network" && ns.Path == "" && !c.Config.NetworkDisabled {
   721  			target, err := os.Readlink(filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"))
   722  			if err != nil {
   723  				return nil, err
   724  			}
   725  
   726  			s.Hooks = specs.Hooks{
   727  				Prestart: []specs.Hook{{
   728  					Path: target, // FIXME: cross-platform
   729  					Args: []string{"libnetwork-setkey", c.ID, daemon.netController.ID()},
   730  				}},
   731  			}
   732  		}
   733  	}
   734  
   735  	if apparmor.IsEnabled() {
   736  		var appArmorProfile string
   737  		if c.AppArmorProfile != "" {
   738  			appArmorProfile = c.AppArmorProfile
   739  		} else if c.HostConfig.Privileged {
   740  			appArmorProfile = "unconfined"
   741  		} else {
   742  			appArmorProfile = "docker-default"
   743  		}
   744  
   745  		if appArmorProfile == "docker-default" {
   746  			// Unattended upgrades and other fun services can unload AppArmor
   747  			// profiles inadvertently. Since we cannot store our profile in
   748  			// /etc/apparmor.d, nor can we practically add other ways of
   749  			// telling the system to keep our profile loaded, in order to make
   750  			// sure that we keep the default profile enabled we dynamically
   751  			// reload it if necessary.
   752  			if err := ensureDefaultAppArmorProfile(); err != nil {
   753  				return nil, err
   754  			}
   755  		}
   756  
   757  		s.Process.ApparmorProfile = appArmorProfile
   758  	}
   759  	s.Process.SelinuxLabel = c.GetProcessLabel()
   760  	s.Process.NoNewPrivileges = c.NoNewPrivileges
   761  	s.Linux.MountLabel = c.MountLabel
   762  
   763  	return (*specs.Spec)(&s), nil
   764  }
   765  
   766  func clearReadOnly(m *specs.Mount) {
   767  	var opt []string
   768  	for _, o := range m.Options {
   769  		if o != "ro" {
   770  			opt = append(opt, o)
   771  		}
   772  	}
   773  	m.Options = opt
   774  }
   775  
   776  // mergeUlimits merge the Ulimits from HostConfig with daemon defaults, and update HostConfig
   777  func (daemon *Daemon) mergeUlimits(c *containertypes.HostConfig) {
   778  	ulimits := c.Ulimits
   779  	// Merge ulimits with daemon defaults
   780  	ulIdx := make(map[string]struct{})
   781  	for _, ul := range ulimits {
   782  		ulIdx[ul.Name] = struct{}{}
   783  	}
   784  	for name, ul := range daemon.configStore.Ulimits {
   785  		if _, exists := ulIdx[name]; !exists {
   786  			ulimits = append(ulimits, ul)
   787  		}
   788  	}
   789  	c.Ulimits = ulimits
   790  }