Browse code

Merge pull request #31266 from vieux/17.03-cherry

17.03 cherry-picks

Victor Vieux authored on 2017/02/23 19:02:52
Showing 7 changed files
... ...
@@ -22,6 +22,7 @@ Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk.
22 22
 ### Contrib
23 23
 
24 24
 * Update various `bash` and `zsh` completion scripts [#30823](https://github.com/docker/docker/pull/30823), [#30945](https://github.com/docker/docker/pull/30945) and more...
25
+* Block obsolete socket families in default seccomp profile - mitigates unpatched kernels' CVE-2017-6074 [#29076](https://github.com/docker/docker/pull/29076)
25 26
 
26 27
 ### Networking
27 28
 
... ...
@@ -36,6 +37,14 @@ Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk.
36 36
 
37 37
 * Fix a deadlock in docker logs [#30223](https://github.com/docker/docker/pull/30223)
38 38
 * Fix cpu spin waiting for log write events [#31070](https://github.com/docker/docker/pull/31070)
39
+* Fix a possible crash when using journald [#31231](https://github.com/docker/docker/pull/31231) [#31263](https://github.com/docker/docker/pull/31231)
40
+* Fix a panic on close of nil channel [#31274](https://github.com/docker/docker/pull/31274)
41
+* Fix duplicate mount point for `--volumes-from` in `docker run` [#29563](https://github.com/docker/docker/pull/29563)
42
+* Fix `--cache-from` does not cache last step [#31189](https://github.com/docker/docker/pull/31189)
43
+
44
+### Swarm Mode
45
+
46
+* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279)
39 47
 
40 48
 ### Swarm Mode
41 49
 
... ...
@@ -215,7 +215,7 @@ func isValidParent(img, parent *image.Image) bool {
215 215
 	if len(parent.History) >= len(img.History) {
216 216
 		return false
217 217
 	}
218
-	if len(parent.RootFS.DiffIDs) >= len(img.RootFS.DiffIDs) {
218
+	if len(parent.RootFS.DiffIDs) > len(img.RootFS.DiffIDs) {
219 219
 		return false
220 220
 	}
221 221
 
... ...
@@ -323,8 +323,10 @@ func (r *controller) Shutdown(ctx context.Context) error {
323 323
 
324 324
 	// remove container from service binding
325 325
 	if err := r.adapter.deactivateServiceBinding(); err != nil {
326
-		log.G(ctx).WithError(err).Errorf("failed to deactivate service binding for container %s", r.adapter.container.name())
327
-		return err
326
+		log.G(ctx).WithError(err).Warningf("failed to deactivate service binding for container %s", r.adapter.container.name())
327
+		// Don't return an error here, because failure to deactivate
328
+		// the service binding is expected if the container was never
329
+		// started.
328 330
 	}
329 331
 
330 332
 	if err := r.adapter.shutdown(ctx); err != nil {
... ...
@@ -237,7 +237,10 @@ drain:
237 237
 
238 238
 	// free(NULL) is safe
239 239
 	C.free(unsafe.Pointer(oldCursor))
240
-	C.sd_journal_get_cursor(j, &cursor)
240
+	if C.sd_journal_get_cursor(j, &cursor) != 0 {
241
+		// ensure that we won't be freeing an address that's invalid
242
+		cursor = nil
243
+	}
241 244
 	return cursor
242 245
 }
243 246
 
... ...
@@ -245,6 +248,9 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
245 245
 	s.readers.mu.Lock()
246 246
 	s.readers.readers[logWatcher] = logWatcher
247 247
 	s.readers.mu.Unlock()
248
+
249
+	newCursor := make(chan *C.char)
250
+
248 251
 	go func() {
249 252
 		// Keep copying journal data out until we're notified to stop
250 253
 		// or we hit an error.
... ...
@@ -264,8 +270,8 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
264 264
 		s.readers.mu.Lock()
265 265
 		delete(s.readers.readers, logWatcher)
266 266
 		s.readers.mu.Unlock()
267
-		C.sd_journal_close(j)
268 267
 		close(logWatcher.Msg)
268
+		newCursor <- cursor
269 269
 	}()
270 270
 	// Wait until we're told to stop.
271 271
 	select {
... ...
@@ -274,6 +280,8 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
274 274
 		C.close(pfd[1])
275 275
 	}
276 276
 
277
+	cursor = <-newCursor
278
+
277 279
 	return cursor
278 280
 }
279 281
 
... ...
@@ -298,9 +306,9 @@ func (s *journald) readLogs(logWatcher *logger.LogWatcher, config logger.ReadCon
298 298
 	following := false
299 299
 	defer func(pfollowing *bool) {
300 300
 		if !*pfollowing {
301
-			C.sd_journal_close(j)
302 301
 			close(logWatcher.Msg)
303 302
 		}
303
+		C.sd_journal_close(j)
304 304
 	}(&following)
305 305
 	// Remove limits on the size of data items that we'll retrieve.
306 306
 	rc = C.sd_journal_set_data_threshold(j, C.size_t(0))
... ...
@@ -85,6 +85,15 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
85 85
 		}
86 86
 	}()
87 87
 
88
+	dereferenceIfExists := func(destination string) {
89
+		if v, ok := mountPoints[destination]; ok {
90
+			logrus.Debugf("Duplicate mount point '%s'", destination)
91
+			if v.Volume != nil {
92
+				daemon.volumes.Dereference(v.Volume, container.ID)
93
+			}
94
+		}
95
+	}
96
+
88 97
 	// 1. Read already configured mount points.
89 98
 	for destination, point := range container.MountPoints {
90 99
 		mountPoints[destination] = point
... ...
@@ -121,7 +130,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
121 121
 				}
122 122
 				cp.Volume = v
123 123
 			}
124
-
124
+			dereferenceIfExists(cp.Destination)
125 125
 			mountPoints[cp.Destination] = cp
126 126
 		}
127 127
 	}
... ...
@@ -155,6 +164,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
155 155
 		}
156 156
 
157 157
 		binds[bind.Destination] = true
158
+		dereferenceIfExists(bind.Destination)
158 159
 		mountPoints[bind.Destination] = bind
159 160
 	}
160 161
 
... ...
@@ -199,6 +209,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
199 199
 		}
200 200
 
201 201
 		binds[mp.Destination] = true
202
+		dereferenceIfExists(mp.Destination)
202 203
 		mountPoints[mp.Destination] = mp
203 204
 	}
204 205
 
... ...
@@ -7081,6 +7081,27 @@ func (s *DockerSuite) TestBuildWithFailure(c *check.C) {
7081 7081
 	c.Assert(stdout, checker.Not(checker.Contains), "Step 2/2 : RUN nobody")
7082 7082
 }
7083 7083
 
7084
+func (s *DockerSuite) TestBuildCacheFromEqualDiffIDsLength(c *check.C) {
7085
+	dockerfile := `
7086
+		FROM busybox
7087
+		RUN echo "test"
7088
+		ENTRYPOINT ["sh"]`
7089
+	ctx, err := fakeContext(dockerfile, map[string]string{
7090
+		"Dockerfile": dockerfile,
7091
+	})
7092
+	c.Assert(err, checker.IsNil)
7093
+	defer ctx.Close()
7094
+
7095
+	id1, err := buildImageFromContext("build1", ctx, true)
7096
+	c.Assert(err, checker.IsNil)
7097
+
7098
+	// rebuild with cache-from
7099
+	id2, out, err := buildImageFromContextWithOut("build2", ctx, true, "--cache-from=build1")
7100
+	c.Assert(err, checker.IsNil)
7101
+	c.Assert(id1, checker.Equals, id2)
7102
+	c.Assert(strings.Count(out, "Using cache"), checker.Equals, 2)
7103
+}
7104
+
7084 7105
 func (s *DockerSuite) TestBuildCacheFrom(c *check.C) {
7085 7106
 	testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
7086 7107
 	dockerfile := `
... ...
@@ -3,6 +3,7 @@ package main
3 3
 import (
4 4
 	"fmt"
5 5
 	"io/ioutil"
6
+	"net/http"
6 7
 	"os"
7 8
 	"os/exec"
8 9
 	"path/filepath"
... ...
@@ -425,3 +426,162 @@ func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
425 425
 	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k2, v2))
426 426
 	c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k3, v3))
427 427
 }
428
+
429
+// Test case (1) for 21845: duplicate targets for --volumes-from
430
+func (s *DockerSuite) TestDuplicateMountpointsForVolumesFrom(c *check.C) {
431
+	testRequires(c, DaemonIsLinux)
432
+
433
+	image := "vimage"
434
+	_, err := buildImage(
435
+		image,
436
+		`
437
+    FROM busybox
438
+    VOLUME ["/tmp/data"]
439
+    `,
440
+		true)
441
+	c.Assert(err, check.IsNil)
442
+
443
+	dockerCmd(c, "run", "--name=data1", image, "true")
444
+	dockerCmd(c, "run", "--name=data2", image, "true")
445
+
446
+	out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
447
+	data1 := strings.TrimSpace(out)
448
+	c.Assert(data1, checker.Not(checker.Equals), "")
449
+
450
+	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
451
+	data2 := strings.TrimSpace(out)
452
+	c.Assert(data2, checker.Not(checker.Equals), "")
453
+
454
+	// Both volume should exist
455
+	out, _ = dockerCmd(c, "volume", "ls", "-q")
456
+	c.Assert(strings.TrimSpace(out), checker.Contains, data1)
457
+	c.Assert(strings.TrimSpace(out), checker.Contains, data2)
458
+
459
+	out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-d", "busybox", "top")
460
+	c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
461
+
462
+	// Only the second volume will be referenced, this is backward compatible
463
+	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
464
+	c.Assert(strings.TrimSpace(out), checker.Equals, data2)
465
+
466
+	dockerCmd(c, "rm", "-f", "-v", "app")
467
+	dockerCmd(c, "rm", "-f", "-v", "data1")
468
+	dockerCmd(c, "rm", "-f", "-v", "data2")
469
+
470
+	// Both volume should not exist
471
+	out, _ = dockerCmd(c, "volume", "ls", "-q")
472
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
473
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
474
+}
475
+
476
+// Test case (2) for 21845: duplicate targets for --volumes-from and -v (bind)
477
+func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndBind(c *check.C) {
478
+	testRequires(c, DaemonIsLinux)
479
+
480
+	image := "vimage"
481
+	_, err := buildImage(image,
482
+		`
483
+    FROM busybox
484
+    VOLUME ["/tmp/data"]
485
+    `,
486
+		true)
487
+	c.Assert(err, check.IsNil)
488
+
489
+	dockerCmd(c, "run", "--name=data1", image, "true")
490
+	dockerCmd(c, "run", "--name=data2", image, "true")
491
+
492
+	out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
493
+	data1 := strings.TrimSpace(out)
494
+	c.Assert(data1, checker.Not(checker.Equals), "")
495
+
496
+	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
497
+	data2 := strings.TrimSpace(out)
498
+	c.Assert(data2, checker.Not(checker.Equals), "")
499
+
500
+	// Both volume should exist
501
+	out, _ = dockerCmd(c, "volume", "ls", "-q")
502
+	c.Assert(strings.TrimSpace(out), checker.Contains, data1)
503
+	c.Assert(strings.TrimSpace(out), checker.Contains, data2)
504
+
505
+	out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-v", "/tmp/data:/tmp/data", "-d", "busybox", "top")
506
+	c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
507
+
508
+	// No volume will be referenced (mount is /tmp/data), this is backward compatible
509
+	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
510
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
511
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
512
+
513
+	dockerCmd(c, "rm", "-f", "-v", "app")
514
+	dockerCmd(c, "rm", "-f", "-v", "data1")
515
+	dockerCmd(c, "rm", "-f", "-v", "data2")
516
+
517
+	// Both volume should not exist
518
+	out, _ = dockerCmd(c, "volume", "ls", "-q")
519
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
520
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
521
+}
522
+
523
+// Test case (3) for 21845: duplicate targets for --volumes-from and `Mounts` (API only)
524
+func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndMounts(c *check.C) {
525
+	testRequires(c, DaemonIsLinux)
526
+
527
+	image := "vimage"
528
+	_, err := buildImage(image,
529
+		`
530
+    FROM busybox
531
+    VOLUME ["/tmp/data"]
532
+    `,
533
+		true)
534
+	c.Assert(err, check.IsNil)
535
+
536
+	dockerCmd(c, "run", "--name=data1", image, "true")
537
+	dockerCmd(c, "run", "--name=data2", image, "true")
538
+
539
+	out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
540
+	data1 := strings.TrimSpace(out)
541
+	c.Assert(data1, checker.Not(checker.Equals), "")
542
+
543
+	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
544
+	data2 := strings.TrimSpace(out)
545
+	c.Assert(data2, checker.Not(checker.Equals), "")
546
+
547
+	// Both volume should exist
548
+	out, _ = dockerCmd(c, "volume", "ls", "-q")
549
+	c.Assert(strings.TrimSpace(out), checker.Contains, data1)
550
+	c.Assert(strings.TrimSpace(out), checker.Contains, data2)
551
+
552
+	// Mounts is available in API
553
+	status, body, err := sockRequest("POST", "/containers/create?name=app", map[string]interface{}{
554
+		"Image": "busybox",
555
+		"Cmd":   []string{"top"},
556
+		"HostConfig": map[string]interface{}{
557
+			"VolumesFrom": []string{
558
+				"data1",
559
+				"data2",
560
+			},
561
+			"Mounts": []map[string]interface{}{
562
+				{
563
+					"Type":   "bind",
564
+					"Source": "/tmp/data",
565
+					"Target": "/tmp/data",
566
+				},
567
+			}},
568
+	})
569
+
570
+	c.Assert(err, checker.IsNil, check.Commentf(string(body)))
571
+	c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body)))
572
+
573
+	// No volume will be referenced (mount is /tmp/data), this is backward compatible
574
+	out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
575
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
576
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
577
+
578
+	dockerCmd(c, "rm", "-f", "-v", "app")
579
+	dockerCmd(c, "rm", "-f", "-v", "data1")
580
+	dockerCmd(c, "rm", "-f", "-v", "data2")
581
+
582
+	// Both volume should not exist
583
+	out, _ = dockerCmd(c, "volume", "ls", "-q")
584
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
585
+	c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
586
+}