create.go 7.1 KB

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