oci_linux.go 18 KB

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