Browse code

libcontainer: Don't use UsetCloseOnExec, it is racy

We can't keep file descriptors without close-on-exec except with
syscall.ForkLock held, as otherwise they could leak by accident into
other children from forks in other threads.

Instead we just use Cmd.ExtraFiles which handles all this for us.

This fixes https://github.com/dotcloud/docker/issues/4493

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)

Alexander Larsson authored on 2014/03/06 22:10:32
Showing 4 changed files
... ...
@@ -239,7 +239,7 @@ type dockerCommandFactory struct {
239 239
 // createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
240 240
 // defined on the container's configuration and use the current binary as the init with the
241 241
 // args provided
242
-func (d *dockerCommandFactory) Create(container *libcontainer.Container, console string, syncFd uintptr, args []string) *exec.Cmd {
242
+func (d *dockerCommandFactory) Create(container *libcontainer.Container, console string, syncFile *os.File, args []string) *exec.Cmd {
243 243
 	// we need to join the rootfs because nsinit will setup the rootfs and chroot
244 244
 	initPath := filepath.Join(d.c.Rootfs, d.c.InitPath)
245 245
 
... ...
@@ -248,7 +248,7 @@ func (d *dockerCommandFactory) Create(container *libcontainer.Container, console
248 248
 		initPath,
249 249
 		"-driver", DriverName,
250 250
 		"-console", console,
251
-		"-pipe", fmt.Sprint(syncFd),
251
+		"-pipe", "3",
252 252
 		"-root", filepath.Join(d.driver.root, d.c.ID),
253 253
 		"--",
254 254
 	}, args...)
... ...
@@ -256,6 +256,7 @@ func (d *dockerCommandFactory) Create(container *libcontainer.Container, console
256 256
 	// set this to nil so that when we set the clone flags anything else is reset
257 257
 	d.c.SysProcAttr = nil
258 258
 	system.SetCloneFlags(&d.c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
259
+	d.c.ExtraFiles = []*os.File{syncFile}
259 260
 
260 261
 	d.c.Env = container.Env
261 262
 	d.c.Dir = d.c.Rootfs
... ...
@@ -1,7 +1,6 @@
1 1
 package nsinit
2 2
 
3 3
 import (
4
-	"fmt"
5 4
 	"github.com/dotcloud/docker/pkg/libcontainer"
6 5
 	"github.com/dotcloud/docker/pkg/system"
7 6
 	"os"
... ...
@@ -12,7 +11,7 @@ import (
12 12
 // parent processes and creates an *exec.Cmd that will be used to fork/exec the
13 13
 // namespaced init process
14 14
 type CommandFactory interface {
15
-	Create(container *libcontainer.Container, console string, syncFd uintptr, args []string) *exec.Cmd
15
+	Create(container *libcontainer.Container, console string, syncFd *os.File, args []string) *exec.Cmd
16 16
 }
17 17
 
18 18
 type DefaultCommandFactory struct {
... ...
@@ -22,16 +21,17 @@ type DefaultCommandFactory struct {
22 22
 // Create will return an exec.Cmd with the Cloneflags set to the proper namespaces
23 23
 // defined on the container's configuration and use the current binary as the init with the
24 24
 // args provided
25
-func (c *DefaultCommandFactory) Create(container *libcontainer.Container, console string, pipe uintptr, args []string) *exec.Cmd {
25
+func (c *DefaultCommandFactory) Create(container *libcontainer.Container, console string, pipe *os.File, args []string) *exec.Cmd {
26 26
 	// get our binary name from arg0 so we can always reexec ourself
27 27
 	command := exec.Command(os.Args[0], append([]string{
28 28
 		"-console", console,
29
-		"-pipe", fmt.Sprint(pipe),
29
+		"-pipe", "3",
30 30
 		"-root", c.Root,
31 31
 		"init"}, args...)...)
32 32
 
33 33
 	system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces)))
34 34
 	command.Env = container.Env
35
+	command.ExtraFiles = []*os.File{pipe}
35 36
 	return command
36 37
 }
37 38
 
... ...
@@ -35,7 +35,7 @@ func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, args [
35 35
 		term.SetMaster(master)
36 36
 	}
37 37
 
38
-	command := ns.commandFactory.Create(container, console, syncPipe.child.Fd(), args)
38
+	command := ns.commandFactory.Create(container, console, syncPipe.child, args)
39 39
 	if err := term.Attach(command); err != nil {
40 40
 		return -1, err
41 41
 	}
... ...
@@ -4,7 +4,6 @@ import (
4 4
 	"encoding/json"
5 5
 	"fmt"
6 6
 	"github.com/dotcloud/docker/pkg/libcontainer"
7
-	"github.com/dotcloud/docker/pkg/system"
8 7
 	"io/ioutil"
9 8
 	"os"
10 9
 )
... ...
@@ -22,7 +21,6 @@ func NewSyncPipe() (s *SyncPipe, err error) {
22 22
 	if err != nil {
23 23
 		return nil, err
24 24
 	}
25
-	system.UsetCloseOnExec(s.child.Fd())
26 25
 	return s, nil
27 26
 }
28 27