Remove --read-only restriction when user ns enabled
| ... | ... |
@@ -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) {
|