Skip to content

Commit 8ac2000

Browse files
authored
Merge pull request moby#25540 from estesp/ro-plus-userns
Remove --read-only restriction when user ns enabled
2 parents 3ae023c + 6062ae5 commit 8ac2000

File tree

4 files changed

+34
-22
lines changed

4 files changed

+34
-22
lines changed

daemon/daemon_unix.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,6 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
496496
if hostConfig.PidMode.IsHost() && !hostConfig.UsernsMode.IsHost() {
497497
return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled")
498498
}
499-
if hostConfig.ReadonlyRootfs {
500-
return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled")
501-
}
502499
}
503500
if hostConfig.CgroupParent != "" && UsingSystemd(daemon.configStore) {
504501
// CgroupParent for systemd cgroup should be named as "xxx.slice"

docs/reference/commandline/dockerd.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -955,16 +955,16 @@ This option will completely disable user namespace mapping for the container's u
955955
The following standard Docker features are currently incompatible when
956956
running a Docker daemon with user namespaces enabled:
957957
958-
- sharing PID or NET namespaces with the host (`--pid=host` or `--network=host`)
959-
- A `--read-only` container filesystem (this is a Linux kernel restriction against remounting with modified flags of a currently mounted filesystem when inside a user namespace)
960-
- external (volume or graph) drivers which are unaware/incapable of using daemon user mappings
958+
- sharing PID or NET namespaces with the host (`--pid=host` or `--net=host`)
961959
- Using `--privileged` mode flag on `docker run` (unless also specifying `--userns=host`)
962960
963961
In general, user namespaces are an advanced feature and will require
964962
coordination with other capabilities. For example, if volumes are mounted from
965963
the host, file ownership will have to be pre-arranged if the user or
966964
administrator wishes the containers to have expected access to the volume
967-
contents.
965+
contents. Note that when using external volume or graph driver plugins, those
966+
external software programs must be made aware of user and group mapping ranges
967+
if they are to work seamlessly with user namespace support.
968968
969969
Finally, while the `root` user inside a user namespaced container process has
970970
many of the expected admin privileges that go along with being the superuser, the

integration-cli/docker_cli_run_test.go

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2859,16 +2859,20 @@ func (s *DockerSuite) TestRunContainerWithWritableRootfs(c *check.C) {
28592859

28602860
func (s *DockerSuite) TestRunContainerWithReadonlyRootfs(c *check.C) {
28612861
// Not applicable on Windows which does not support --read-only
2862-
testRequires(c, DaemonIsLinux)
2862+
testRequires(c, DaemonIsLinux, UserNamespaceROMount)
28632863

2864-
testReadOnlyFile(c, "/file", "/etc/hosts", "/etc/resolv.conf", "/etc/hostname", "/sys/kernel", "/dev/.dont.touch.me")
2864+
testPriv := true
2865+
// don't test privileged mode subtest if user namespaces enabled
2866+
if root := os.Getenv("DOCKER_REMAP_ROOT"); root != "" {
2867+
testPriv = false
2868+
}
2869+
testReadOnlyFile(c, testPriv, "/file", "/etc/hosts", "/etc/resolv.conf", "/etc/hostname", "/sys/kernel", "/dev/.dont.touch.me")
28652870
}
28662871

28672872
func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) {
28682873
// Not applicable on Windows due to use of Unix specific functionality, plus
28692874
// the use of --read-only which is not supported.
2870-
// --read-only + userns has remount issues
2871-
testRequires(c, DaemonIsLinux, NotUserNamespace)
2875+
testRequires(c, DaemonIsLinux, UserNamespaceROMount)
28722876

28732877
// Ensure we have not broken writing /dev/pts
28742878
out, status := dockerCmd(c, "run", "--read-only", "--rm", "busybox", "mount")
@@ -2881,9 +2885,7 @@ func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) {
28812885
}
28822886
}
28832887

2884-
func testReadOnlyFile(c *check.C, filenames ...string) {
2885-
// Not applicable on Windows which does not support --read-only
2886-
testRequires(c, DaemonIsLinux, NotUserNamespace)
2888+
func testReadOnlyFile(c *check.C, testPriv bool, filenames ...string) {
28872889
touch := "touch " + strings.Join(filenames, " ")
28882890
out, _, err := dockerCmdWithError("run", "--read-only", "--rm", "busybox", "sh", "-c", touch)
28892891
c.Assert(err, checker.NotNil)
@@ -2893,6 +2895,10 @@ func testReadOnlyFile(c *check.C, filenames ...string) {
28932895
c.Assert(out, checker.Contains, expected)
28942896
}
28952897

2898+
if !testPriv {
2899+
return
2900+
}
2901+
28962902
out, _, err = dockerCmdWithError("run", "--read-only", "--privileged", "--rm", "busybox", "sh", "-c", touch)
28972903
c.Assert(err, checker.NotNil)
28982904

@@ -2904,8 +2910,7 @@ func testReadOnlyFile(c *check.C, filenames ...string) {
29042910

29052911
func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *check.C) {
29062912
// Not applicable on Windows which does not support --link
2907-
// --read-only + userns has remount issues
2908-
testRequires(c, DaemonIsLinux, NotUserNamespace)
2913+
testRequires(c, DaemonIsLinux, UserNamespaceROMount)
29092914

29102915
dockerCmd(c, "run", "-d", "--name", "test-etc-hosts-ro-linked", "busybox", "top")
29112916

@@ -2917,8 +2922,7 @@ func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *
29172922

29182923
func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDNSFlag(c *check.C) {
29192924
// Not applicable on Windows which does not support either --read-only or --dns.
2920-
// --read-only + userns has remount issues
2921-
testRequires(c, DaemonIsLinux, NotUserNamespace)
2925+
testRequires(c, DaemonIsLinux, UserNamespaceROMount)
29222926

29232927
out, _ := dockerCmd(c, "run", "--read-only", "--dns", "1.1.1.1", "busybox", "/bin/cat", "/etc/resolv.conf")
29242928
if !strings.Contains(string(out), "1.1.1.1") {
@@ -2928,8 +2932,7 @@ func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDNSFlag(c *check.C)
29282932

29292933
func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithAddHostFlag(c *check.C) {
29302934
// Not applicable on Windows which does not support --read-only
2931-
// --read-only + userns has remount issues
2932-
testRequires(c, DaemonIsLinux, NotUserNamespace)
2935+
testRequires(c, DaemonIsLinux, UserNamespaceROMount)
29332936

29342937
out, _ := dockerCmd(c, "run", "--read-only", "--add-host", "testreadonly:127.0.0.1", "busybox", "/bin/cat", "/etc/hosts")
29352938
if !strings.Contains(string(out), "testreadonly") {
@@ -3284,8 +3287,7 @@ func (s *DockerSuite) TestRunNetworkFilesBindMountRO(c *check.C) {
32843287

32853288
func (s *DockerSuite) TestRunNetworkFilesBindMountROFilesystem(c *check.C) {
32863289
// Not applicable on Windows as uses Unix specific functionality
3287-
// --read-only + userns has remount issues
3288-
testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
3290+
testRequires(c, SameHostDaemon, DaemonIsLinux, UserNamespaceROMount)
32893291

32903292
filename := createTmpFile(c, "test123")
32913293
defer os.Remove(filename)

integration-cli/requirements.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,19 @@ var (
153153
},
154154
"Test requires support for IPv6",
155155
}
156+
UserNamespaceROMount = testRequirement{
157+
func() bool {
158+
// quick case--userns not enabled in this test run
159+
if os.Getenv("DOCKER_REMAP_ROOT") == "" {
160+
return true
161+
}
162+
if _, _, err := dockerCmdWithError("run", "--rm", "--read-only", "busybox", "date"); err != nil {
163+
return false
164+
}
165+
return true
166+
},
167+
"Test cannot be run if user namespaces enabled but readonly mounts fail on this kernel.",
168+
}
156169
UserNamespaceInKernel = testRequirement{
157170
func() bool {
158171
if _, err := os.Stat("/proc/self/uid_map"); os.IsNotExist(err) {

0 commit comments

Comments
 (0)