Browse code

Fix user mount /dev/shm size

Commit 7120976d74195 ("Implement none, private, and shareable ipc
modes") introduces a bug: if a user-specified mount for /dev/shm
is provided, its size is overriden by value of ShmSize.

A reproducer is simple:

docker run --rm
--mount type=tmpfs,dst=/dev/shm,tmpfs-size=100K \
alpine df /dev/shm

This commit is an attempt to fix the bug, as well as optimize things
a but and make the code easier to read.

https://github.com/moby/moby/issues/35271

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>

Kir Kolyshkin authored on 2017/10/27 16:21:41
Showing 1 changed files
... ...
@@ -528,23 +528,35 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
528 528
 		userMounts[m.Destination] = struct{}{}
529 529
 	}
530 530
 
531
-	// Filter out mounts from spec
532
-	noIpc := c.HostConfig.IpcMode.IsNone()
533
-	// Filter out mounts that are overridden by user supplied mounts
531
+	// Copy all mounts from spec to defaultMounts, except for
532
+	//  - mounts overriden by a user supplied mount;
533
+	//  - all mounts under /dev if a user supplied /dev is present;
534
+	//  - /dev/shm, in case IpcMode is none.
535
+	// While at it, also
536
+	//  - set size for /dev/shm from shmsize.
534 537
 	var defaultMounts []specs.Mount
535 538
 	_, mountDev := userMounts["/dev"]
536 539
 	for _, m := range s.Mounts {
537
-		// filter out /dev/shm mount if case IpcMode is none
538
-		if noIpc && m.Destination == "/dev/shm" {
540
+		if _, ok := userMounts[m.Destination]; ok {
541
+			// filter out mount overridden by a user supplied mount
539 542
 			continue
540 543
 		}
541
-		// filter out mount overridden by a user supplied mount
542
-		if _, ok := userMounts[m.Destination]; !ok {
543
-			if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
544
+		if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
545
+			// filter out everything under /dev if /dev is user-mounted
546
+			continue
547
+		}
548
+
549
+		if m.Destination == "/dev/shm" {
550
+			if c.HostConfig.IpcMode.IsNone() {
551
+				// filter out /dev/shm for "none" IpcMode
544 552
 				continue
545 553
 			}
546
-			defaultMounts = append(defaultMounts, m)
554
+			// set size for /dev/shm mount from spec
555
+			sizeOpt := "size=" + strconv.FormatInt(c.HostConfig.ShmSize, 10)
556
+			m.Options = append(m.Options, sizeOpt)
547 557
 		}
558
+
559
+		defaultMounts = append(defaultMounts, m)
548 560
 	}
549 561
 
550 562
 	s.Mounts = defaultMounts
... ...
@@ -652,14 +664,6 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
652 652
 		s.Linux.MaskedPaths = nil
653 653
 	}
654 654
 
655
-	// Set size for /dev/shm mount that comes from spec (IpcMode: private only)
656
-	for i, m := range s.Mounts {
657
-		if m.Destination == "/dev/shm" {
658
-			sizeOpt := "size=" + strconv.FormatInt(c.HostConfig.ShmSize, 10)
659
-			s.Mounts[i].Options = append(s.Mounts[i].Options, sizeOpt)
660
-		}
661
-	}
662
-
663 655
 	// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
664 656
 	// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
665 657
 	if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {