diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index fbb09737fc..d085574741 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -301,3 +301,14 @@ func TestDockerRunWithRelativePath(t *testing.T) { logDone("run - volume with relative path") } + +func TestVolumesMountedAsReadonly(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-v", "/test:/test:ro", "busybox", "touch", "/test/somefile") + if code, err := runCommand(cmd); err == nil || code == 0 { + t.Fatalf("run should fail because volume is ro: exit code %d", code) + } + + deleteAllContainers() + + logDone("run - volumes as readonly mount") +} diff --git a/pkg/libcontainer/nsinit/mount.go b/pkg/libcontainer/nsinit/mount.go index 4b5a42b1ac..3b0cf13bc9 100644 --- a/pkg/libcontainer/nsinit/mount.go +++ b/pkg/libcontainer/nsinit/mount.go @@ -37,14 +37,21 @@ func setupNewMountNamespace(rootfs string, bindMounts []libcontainer.Mount, cons } for _, m := range bindMounts { - flags := syscall.MS_BIND | syscall.MS_REC + var ( + flags = syscall.MS_BIND | syscall.MS_REC + dest = filepath.Join(rootfs, m.Destination) + ) if !m.Writable { flags = flags | syscall.MS_RDONLY } - dest := filepath.Join(rootfs, m.Destination) if err := system.Mount(m.Source, dest, "bind", uintptr(flags), ""); err != nil { return fmt.Errorf("mounting %s into %s %s", m.Source, dest, err) } + if !m.Writable { + if err := system.Mount(m.Source, dest, "bind", uintptr(flags|syscall.MS_REMOUNT), ""); err != nil { + return fmt.Errorf("remounting %s into %s %s", m.Source, dest, err) + } + } if m.Private { if err := system.Mount("", dest, "none", uintptr(syscall.MS_PRIVATE), ""); err != nil { return fmt.Errorf("mounting %s private %s", dest, err)