oci_linux.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  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 overridden 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. data := c.HostConfig.Tmpfs[m.Destination]
  440. options := []string{"noexec", "nosuid", "nodev", volume.DefaultPropagationMode}
  441. if data != "" {
  442. options = append(options, strings.Split(data, ",")...)
  443. }
  444. merged, err := mount.MergeTmpfsOptions(options)
  445. if err != nil {
  446. return err
  447. }
  448. s.Mounts = append(s.Mounts, specs.Mount{Destination: m.Destination, Source: m.Source, Type: "tmpfs", Options: merged})
  449. continue
  450. }
  451. mt := specs.Mount{Destination: m.Destination, Source: m.Source, Type: "bind"}
  452. // Determine property of RootPropagation based on volume
  453. // properties. If a volume is shared, then keep root propagation
  454. // shared. This should work for slave and private volumes too.
  455. //
  456. // For slave volumes, it can be either [r]shared/[r]slave.
  457. //
  458. // For private volumes any root propagation value should work.
  459. pFlag := mountPropagationMap[m.Propagation]
  460. if pFlag == mount.SHARED || pFlag == mount.RSHARED {
  461. if err := ensureShared(m.Source); err != nil {
  462. return err
  463. }
  464. rootpg := mountPropagationMap[s.Linux.RootfsPropagation]
  465. if rootpg != mount.SHARED && rootpg != mount.RSHARED {
  466. s.Linux.RootfsPropagation = mountPropagationReverseMap[mount.SHARED]
  467. }
  468. } else if pFlag == mount.SLAVE || pFlag == mount.RSLAVE {
  469. if err := ensureSharedOrSlave(m.Source); err != nil {
  470. return err
  471. }
  472. rootpg := mountPropagationMap[s.Linux.RootfsPropagation]
  473. if rootpg != mount.SHARED && rootpg != mount.RSHARED && rootpg != mount.SLAVE && rootpg != mount.RSLAVE {
  474. s.Linux.RootfsPropagation = mountPropagationReverseMap[mount.RSLAVE]
  475. }
  476. }
  477. opts := []string{"rbind"}
  478. if !m.Writable {
  479. opts = append(opts, "ro")
  480. }
  481. if pFlag != 0 {
  482. opts = append(opts, mountPropagationReverseMap[pFlag])
  483. }
  484. mt.Options = opts
  485. s.Mounts = append(s.Mounts, mt)
  486. }
  487. if s.Root.Readonly {
  488. for i, m := range s.Mounts {
  489. switch m.Destination {
  490. case "/proc", "/dev/pts", "/dev/mqueue": // /dev is remounted by runc
  491. continue
  492. }
  493. if _, ok := userMounts[m.Destination]; !ok {
  494. if !stringutils.InSlice(m.Options, "ro") {
  495. s.Mounts[i].Options = append(s.Mounts[i].Options, "ro")
  496. }
  497. }
  498. }
  499. }
  500. if c.HostConfig.Privileged {
  501. if !s.Root.Readonly {
  502. // clear readonly for /sys
  503. for i := range s.Mounts {
  504. if s.Mounts[i].Destination == "/sys" {
  505. clearReadOnly(&s.Mounts[i])
  506. }
  507. }
  508. }
  509. s.Linux.ReadonlyPaths = nil
  510. s.Linux.MaskedPaths = nil
  511. }
  512. // TODO: until a kernel/mount solution exists for handling remount in a user namespace,
  513. // we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
  514. if uidMap, _ := daemon.GetUIDGIDMaps(); uidMap != nil || c.HostConfig.Privileged {
  515. for i, m := range s.Mounts {
  516. if m.Type == "cgroup" {
  517. clearReadOnly(&s.Mounts[i])
  518. }
  519. }
  520. }
  521. return nil
  522. }
  523. func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) error {
  524. linkedEnv, err := daemon.setupLinkedContainers(c)
  525. if err != nil {
  526. return err
  527. }
  528. s.Root = specs.Root{
  529. Path: c.BaseFS,
  530. Readonly: c.HostConfig.ReadonlyRootfs,
  531. }
  532. rootUID, rootGID := daemon.GetRemappedUIDGID()
  533. if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil {
  534. return err
  535. }
  536. cwd := c.Config.WorkingDir
  537. if len(cwd) == 0 {
  538. cwd = "/"
  539. }
  540. s.Process.Args = append([]string{c.Path}, c.Args...)
  541. s.Process.Cwd = cwd
  542. s.Process.Env = c.CreateDaemonEnvironment(linkedEnv)
  543. s.Process.Terminal = c.Config.Tty
  544. s.Hostname = c.FullHostname()
  545. return nil
  546. }
  547. func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, error) {
  548. s := oci.DefaultSpec()
  549. if err := daemon.populateCommonSpec(&s, c); err != nil {
  550. return nil, err
  551. }
  552. var cgroupsPath string
  553. scopePrefix := "docker"
  554. parent := "/docker"
  555. useSystemd := UsingSystemd(daemon.configStore)
  556. if useSystemd {
  557. parent = "system.slice"
  558. }
  559. if c.HostConfig.CgroupParent != "" {
  560. parent = c.HostConfig.CgroupParent
  561. } else if daemon.configStore.CgroupParent != "" {
  562. parent = daemon.configStore.CgroupParent
  563. }
  564. if useSystemd {
  565. cgroupsPath = parent + ":" + scopePrefix + ":" + c.ID
  566. logrus.Debugf("createSpec: cgroupsPath: %s", cgroupsPath)
  567. } else {
  568. cgroupsPath = filepath.Join(parent, c.ID)
  569. }
  570. s.Linux.CgroupsPath = &cgroupsPath
  571. if err := setResources(&s, c.HostConfig.Resources); err != nil {
  572. return nil, fmt.Errorf("linux runtime spec resources: %v", err)
  573. }
  574. s.Linux.Resources.OOMScoreAdj = &c.HostConfig.OomScoreAdj
  575. s.Linux.Sysctl = c.HostConfig.Sysctls
  576. if err := setDevices(&s, c); err != nil {
  577. return nil, fmt.Errorf("linux runtime spec devices: %v", err)
  578. }
  579. if err := setRlimits(daemon, &s, c); err != nil {
  580. return nil, fmt.Errorf("linux runtime spec rlimits: %v", err)
  581. }
  582. if err := setUser(&s, c); err != nil {
  583. return nil, fmt.Errorf("linux spec user: %v", err)
  584. }
  585. if err := setNamespaces(daemon, &s, c); err != nil {
  586. return nil, fmt.Errorf("linux spec namespaces: %v", err)
  587. }
  588. if err := setCapabilities(&s, c); err != nil {
  589. return nil, fmt.Errorf("linux spec capabilities: %v", err)
  590. }
  591. if err := setSeccomp(daemon, &s, c); err != nil {
  592. return nil, fmt.Errorf("linux seccomp: %v", err)
  593. }
  594. if err := daemon.setupIpcDirs(c); err != nil {
  595. return nil, err
  596. }
  597. ms, err := daemon.setupMounts(c)
  598. if err != nil {
  599. return nil, err
  600. }
  601. ms = append(ms, c.IpcMounts()...)
  602. ms = append(ms, c.TmpfsMounts()...)
  603. sort.Sort(mounts(ms))
  604. if err := setMounts(daemon, &s, c, ms); err != nil {
  605. return nil, fmt.Errorf("linux mounts: %v", err)
  606. }
  607. for _, ns := range s.Linux.Namespaces {
  608. if ns.Type == "network" && ns.Path == "" && !c.Config.NetworkDisabled {
  609. target, err := os.Readlink(filepath.Join("/proc", strconv.Itoa(os.Getpid()), "exe"))
  610. if err != nil {
  611. return nil, err
  612. }
  613. s.Hooks = specs.Hooks{
  614. Prestart: []specs.Hook{{
  615. Path: target, // FIXME: cross-platform
  616. Args: []string{"libnetwork-setkey", c.ID, daemon.netController.ID()},
  617. }},
  618. }
  619. }
  620. }
  621. if apparmor.IsEnabled() {
  622. appArmorProfile := "docker-default"
  623. if len(c.AppArmorProfile) > 0 {
  624. appArmorProfile = c.AppArmorProfile
  625. } else if c.HostConfig.Privileged {
  626. appArmorProfile = "unconfined"
  627. }
  628. s.Process.ApparmorProfile = appArmorProfile
  629. }
  630. s.Process.SelinuxLabel = c.GetProcessLabel()
  631. s.Process.NoNewPrivileges = c.NoNewPrivileges
  632. s.Linux.MountLabel = c.MountLabel
  633. return (*libcontainerd.Spec)(&s), nil
  634. }
  635. func clearReadOnly(m *specs.Mount) {
  636. var opt []string
  637. for _, o := range m.Options {
  638. if o != "ro" {
  639. opt = append(opt, o)
  640. }
  641. }
  642. m.Options = opt
  643. }