Browse code

Merge pull request #25540 from estesp/ro-plus-userns

Remove --read-only restriction when user ns enabled

Sebastiaan van Stijn authored on 2016/09/14 20:53:58
Showing 4 changed files
... ...
@@ -496,9 +496,6 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
496 496
 		if hostConfig.PidMode.IsHost() && !hostConfig.UsernsMode.IsHost() {
497 497
 			return warnings, fmt.Errorf("Cannot share the host PID namespace when user namespaces are enabled")
498 498
 		}
499
-		if hostConfig.ReadonlyRootfs {
500
-			return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled")
501
-		}
502 499
 	}
503 500
 	if hostConfig.CgroupParent != "" && UsingSystemd(daemon.configStore) {
504 501
 		// CgroupParent for systemd cgroup should be named as "xxx.slice"
... ...
@@ -955,16 +955,16 @@ This option will completely disable user namespace mapping for the container's u
955 955
 The following standard Docker features are currently incompatible when
956 956
 running a Docker daemon with user namespaces enabled:
957 957
 
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`)
961 959
  - Using `--privileged` mode flag on `docker run` (unless also specifying `--userns=host`)
962 960
 
963 961
 In general, user namespaces are an advanced feature and will require
964 962
 coordination with other capabilities. For example, if volumes are mounted from
965 963
 the host, file ownership will have to be pre-arranged if the user or
966 964
 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.
968 968
 
969 969
 Finally, while the `root` user inside a user namespaced container process has
970 970
 many of the expected admin privileges that go along with being the superuser, the
... ...
@@ -2859,16 +2859,20 @@ func (s *DockerSuite) TestRunContainerWithWritableRootfs(c *check.C) {
2859 2859
 
2860 2860
 func (s *DockerSuite) TestRunContainerWithReadonlyRootfs(c *check.C) {
2861 2861
 	// Not applicable on Windows which does not support --read-only
2862
-	testRequires(c, DaemonIsLinux)
2862
+	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2863 2863
 
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")
2865 2870
 }
2866 2871
 
2867 2872
 func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) {
2868 2873
 	// Not applicable on Windows due to use of Unix specific functionality, plus
2869 2874
 	// 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)
2872 2876
 
2873 2877
 	// Ensure we have not broken writing /dev/pts
2874 2878
 	out, status := dockerCmd(c, "run", "--read-only", "--rm", "busybox", "mount")
... ...
@@ -2881,9 +2885,7 @@ func (s *DockerSuite) TestPermissionsPtsReadonlyRootfs(c *check.C) {
2881 2881
 	}
2882 2882
 }
2883 2883
 
2884
-func testReadOnlyFile(c *check.C, filenames ...string) {
2885
-	// Not applicable on Windows which does not support --read-only
2886
-	testRequires(c, DaemonIsLinux, NotUserNamespace)
2884
+func testReadOnlyFile(c *check.C, testPriv bool, filenames ...string) {
2887 2885
 	touch := "touch " + strings.Join(filenames, " ")
2888 2886
 	out, _, err := dockerCmdWithError("run", "--read-only", "--rm", "busybox", "sh", "-c", touch)
2889 2887
 	c.Assert(err, checker.NotNil)
... ...
@@ -2893,6 +2895,10 @@ func testReadOnlyFile(c *check.C, filenames ...string) {
2893 2893
 		c.Assert(out, checker.Contains, expected)
2894 2894
 	}
2895 2895
 
2896
+	if !testPriv {
2897
+		return
2898
+	}
2899
+
2896 2900
 	out, _, err = dockerCmdWithError("run", "--read-only", "--privileged", "--rm", "busybox", "sh", "-c", touch)
2897 2901
 	c.Assert(err, checker.NotNil)
2898 2902
 
... ...
@@ -2904,8 +2910,7 @@ func testReadOnlyFile(c *check.C, filenames ...string) {
2904 2904
 
2905 2905
 func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *check.C) {
2906 2906
 	// Not applicable on Windows which does not support --link
2907
-	// --read-only + userns has remount issues
2908
-	testRequires(c, DaemonIsLinux, NotUserNamespace)
2907
+	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2909 2908
 
2910 2909
 	dockerCmd(c, "run", "-d", "--name", "test-etc-hosts-ro-linked", "busybox", "top")
2911 2910
 
... ...
@@ -2917,8 +2922,7 @@ func (s *DockerSuite) TestRunContainerWithReadonlyEtcHostsAndLinkedContainer(c *
2917 2917
 
2918 2918
 func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDNSFlag(c *check.C) {
2919 2919
 	// 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)
2920
+	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2922 2921
 
2923 2922
 	out, _ := dockerCmd(c, "run", "--read-only", "--dns", "1.1.1.1", "busybox", "/bin/cat", "/etc/resolv.conf")
2924 2923
 	if !strings.Contains(string(out), "1.1.1.1") {
... ...
@@ -2928,8 +2932,7 @@ func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithDNSFlag(c *check.C)
2928 2928
 
2929 2929
 func (s *DockerSuite) TestRunContainerWithReadonlyRootfsWithAddHostFlag(c *check.C) {
2930 2930
 	// Not applicable on Windows which does not support --read-only
2931
-	// --read-only + userns has remount issues
2932
-	testRequires(c, DaemonIsLinux, NotUserNamespace)
2931
+	testRequires(c, DaemonIsLinux, UserNamespaceROMount)
2933 2932
 
2934 2933
 	out, _ := dockerCmd(c, "run", "--read-only", "--add-host", "testreadonly:127.0.0.1", "busybox", "/bin/cat", "/etc/hosts")
2935 2934
 	if !strings.Contains(string(out), "testreadonly") {
... ...
@@ -3284,8 +3287,7 @@ func (s *DockerSuite) TestRunNetworkFilesBindMountRO(c *check.C) {
3284 3284
 
3285 3285
 func (s *DockerSuite) TestRunNetworkFilesBindMountROFilesystem(c *check.C) {
3286 3286
 	// Not applicable on Windows as uses Unix specific functionality
3287
-	// --read-only + userns has remount issues
3288
-	testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
3287
+	testRequires(c, SameHostDaemon, DaemonIsLinux, UserNamespaceROMount)
3289 3288
 
3290 3289
 	filename := createTmpFile(c, "test123")
3291 3290
 	defer os.Remove(filename)
... ...
@@ -153,6 +153,19 @@ var (
153 153
 		},
154 154
 		"Test requires support for IPv6",
155 155
 	}
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
+	}
156 169
 	UserNamespaceInKernel = testRequirement{
157 170
 		func() bool {
158 171
 			if _, err := os.Stat("/proc/self/uid_map"); os.IsNotExist(err) {