create.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // +build linux,cgo
  2. package native
  3. import (
  4. "errors"
  5. "fmt"
  6. "net"
  7. "strings"
  8. "syscall"
  9. "github.com/docker/docker/context"
  10. "github.com/docker/docker/daemon/execdriver"
  11. "github.com/opencontainers/runc/libcontainer/apparmor"
  12. "github.com/opencontainers/runc/libcontainer/configs"
  13. "github.com/opencontainers/runc/libcontainer/devices"
  14. "github.com/opencontainers/runc/libcontainer/utils"
  15. )
  16. // createContainer populates and configures the container type with the
  17. // data provided by the execdriver.Command
  18. func (d *Driver) createContainer(ctx context.Context, c *execdriver.Command, hooks execdriver.Hooks) (*configs.Config, error) {
  19. container := execdriver.InitContainer(c)
  20. if err := d.createIpc(container, c); err != nil {
  21. return nil, err
  22. }
  23. if err := d.createPid(container, c); err != nil {
  24. return nil, err
  25. }
  26. if err := d.createUTS(container, c); err != nil {
  27. return nil, err
  28. }
  29. if err := d.createNetwork(ctx, container, c, hooks); err != nil {
  30. return nil, err
  31. }
  32. if c.ProcessConfig.Privileged {
  33. if !container.Readonlyfs {
  34. // clear readonly for /sys
  35. for i := range container.Mounts {
  36. if container.Mounts[i].Destination == "/sys" {
  37. container.Mounts[i].Flags &= ^syscall.MS_RDONLY
  38. }
  39. }
  40. container.ReadonlyPaths = nil
  41. }
  42. // clear readonly for cgroup
  43. for i := range container.Mounts {
  44. if container.Mounts[i].Device == "cgroup" {
  45. container.Mounts[i].Flags &= ^syscall.MS_RDONLY
  46. }
  47. }
  48. container.MaskPaths = nil
  49. if err := d.setPrivileged(container); err != nil {
  50. return nil, err
  51. }
  52. } else {
  53. if err := d.setCapabilities(container, c); err != nil {
  54. return nil, err
  55. }
  56. }
  57. container.AdditionalGroups = c.GroupAdd
  58. if c.AppArmorProfile != "" {
  59. container.AppArmorProfile = c.AppArmorProfile
  60. }
  61. if err := execdriver.SetupCgroups(container, c); err != nil {
  62. return nil, err
  63. }
  64. if container.Readonlyfs {
  65. for i := range container.Mounts {
  66. switch container.Mounts[i].Destination {
  67. case "/proc", "/dev", "/dev/pts":
  68. continue
  69. }
  70. container.Mounts[i].Flags |= syscall.MS_RDONLY
  71. }
  72. /* These paths must be remounted as r/o */
  73. container.ReadonlyPaths = append(container.ReadonlyPaths, "/dev")
  74. }
  75. if err := d.setupMounts(container, c); err != nil {
  76. return nil, err
  77. }
  78. d.setupLabels(container, c)
  79. d.setupRlimits(container, c)
  80. return container, nil
  81. }
  82. func generateIfaceName() (string, error) {
  83. for i := 0; i < 10; i++ {
  84. name, err := utils.GenerateRandomName("veth", 7)
  85. if err != nil {
  86. continue
  87. }
  88. if _, err := net.InterfaceByName(name); err != nil {
  89. if strings.Contains(err.Error(), "no such") {
  90. return name, nil
  91. }
  92. return "", err
  93. }
  94. }
  95. return "", errors.New("Failed to find name for new interface")
  96. }
  97. func (d *Driver) createNetwork(ctx context.Context, container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error {
  98. if c.Network == nil {
  99. return nil
  100. }
  101. if c.Network.ContainerID != "" {
  102. d.Lock()
  103. active := d.activeContainers[c.Network.ContainerID]
  104. d.Unlock()
  105. if active == nil {
  106. return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
  107. }
  108. state, err := active.State()
  109. if err != nil {
  110. return err
  111. }
  112. container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET])
  113. return nil
  114. }
  115. if c.Network.NamespacePath != "" {
  116. container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath)
  117. return nil
  118. }
  119. // only set up prestart hook if the namespace path is not set (this should be
  120. // all cases *except* for --net=host shared networking)
  121. container.Hooks = &configs.Hooks{
  122. Prestart: []configs.Hook{
  123. configs.NewFunctionHook(func(s configs.HookState) error {
  124. if len(hooks.PreStart) > 0 {
  125. for _, fnHook := range hooks.PreStart {
  126. // A closed channel for OOM is returned here as it will be
  127. // non-blocking and return the correct result when read.
  128. chOOM := make(chan struct{})
  129. close(chOOM)
  130. if err := fnHook(ctx, &c.ProcessConfig, s.Pid, chOOM); err != nil {
  131. return err
  132. }
  133. }
  134. }
  135. return nil
  136. }),
  137. },
  138. }
  139. return nil
  140. }
  141. func (d *Driver) createIpc(container *configs.Config, c *execdriver.Command) error {
  142. if c.Ipc.HostIpc {
  143. container.Namespaces.Remove(configs.NEWIPC)
  144. return nil
  145. }
  146. if c.Ipc.ContainerID != "" {
  147. d.Lock()
  148. active := d.activeContainers[c.Ipc.ContainerID]
  149. d.Unlock()
  150. if active == nil {
  151. return fmt.Errorf("%s is not a valid running container to join", c.Ipc.ContainerID)
  152. }
  153. state, err := active.State()
  154. if err != nil {
  155. return err
  156. }
  157. container.Namespaces.Add(configs.NEWIPC, state.NamespacePaths[configs.NEWIPC])
  158. }
  159. return nil
  160. }
  161. func (d *Driver) createPid(container *configs.Config, c *execdriver.Command) error {
  162. if c.Pid.HostPid {
  163. container.Namespaces.Remove(configs.NEWPID)
  164. return nil
  165. }
  166. return nil
  167. }
  168. func (d *Driver) createUTS(container *configs.Config, c *execdriver.Command) error {
  169. if c.UTS.HostUTS {
  170. container.Namespaces.Remove(configs.NEWUTS)
  171. container.Hostname = ""
  172. return nil
  173. }
  174. return nil
  175. }
  176. func (d *Driver) setPrivileged(container *configs.Config) (err error) {
  177. container.Capabilities = execdriver.GetAllCapabilities()
  178. container.Cgroups.AllowAllDevices = true
  179. hostDevices, err := devices.HostDevices()
  180. if err != nil {
  181. return err
  182. }
  183. container.Devices = hostDevices
  184. if apparmor.IsEnabled() {
  185. container.AppArmorProfile = "unconfined"
  186. }
  187. return nil
  188. }
  189. func (d *Driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) {
  190. container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
  191. return err
  192. }
  193. func (d *Driver) setupRlimits(container *configs.Config, c *execdriver.Command) {
  194. if c.Resources == nil {
  195. return
  196. }
  197. for _, rlimit := range c.Resources.Rlimits {
  198. container.Rlimits = append(container.Rlimits, configs.Rlimit{
  199. Type: rlimit.Type,
  200. Hard: rlimit.Hard,
  201. Soft: rlimit.Soft,
  202. })
  203. }
  204. }
  205. func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) error {
  206. userMounts := make(map[string]struct{})
  207. for _, m := range c.Mounts {
  208. userMounts[m.Destination] = struct{}{}
  209. }
  210. // Filter out mounts that are overriden by user supplied mounts
  211. var defaultMounts []*configs.Mount
  212. _, mountDev := userMounts["/dev"]
  213. for _, m := range container.Mounts {
  214. if _, ok := userMounts[m.Destination]; !ok {
  215. if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
  216. continue
  217. }
  218. defaultMounts = append(defaultMounts, m)
  219. }
  220. }
  221. container.Mounts = defaultMounts
  222. for _, m := range c.Mounts {
  223. flags := syscall.MS_BIND | syscall.MS_REC
  224. if !m.Writable {
  225. flags |= syscall.MS_RDONLY
  226. }
  227. if m.Slave {
  228. flags |= syscall.MS_SLAVE
  229. }
  230. container.Mounts = append(container.Mounts, &configs.Mount{
  231. Source: m.Source,
  232. Destination: m.Destination,
  233. Device: "bind",
  234. Flags: flags,
  235. })
  236. }
  237. return nil
  238. }
  239. func (d *Driver) setupLabels(container *configs.Config, c *execdriver.Command) {
  240. container.ProcessLabel = c.ProcessLabel
  241. container.MountLabel = c.MountLabel
  242. }