Browse code

Set selinux label on local volumes from mounts API

When using a volume via the `Binds` API, a shared selinux label is
automatically set.
The `Mounts` API is not setting this, which makes volumes specified via
the mounts API useless when selinux is enabled.

This fix adopts the same selinux label for volumes on the mounts API as on
binds.
Note in the case of both the `Binds` API and the `Mounts` API, the
selinux label is only applied when the volume driver is the `local`
driver.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2017/08/31 02:10:15
Showing 3 changed files
... ...
@@ -207,6 +207,9 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
207 207
 			}); ok {
208 208
 				mp.Source = cv.CachedPath()
209 209
 			}
210
+			if mp.Driver == volume.DefaultDriverName {
211
+				setBindModeIfNull(mp)
212
+			}
210 213
 		}
211 214
 
212 215
 		binds[mp.Destination] = true
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"os"
12 12
 	"path/filepath"
13 13
 	"regexp"
14
+	"runtime"
14 15
 	"strconv"
15 16
 	"strings"
16 17
 	"time"
... ...
@@ -1901,33 +1902,37 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
1901 1901
 	}
1902 1902
 
1903 1903
 	type testCase struct {
1904
-		cfg      mounttypes.Mount
1904
+		spec     mounttypes.Mount
1905 1905
 		expected types.MountPoint
1906 1906
 	}
1907 1907
 
1908
+	var selinuxSharedLabel string
1909
+	if runtime.GOOS == "linux" {
1910
+		selinuxSharedLabel = "z"
1911
+	}
1912
+
1908 1913
 	cases := []testCase{
1909 1914
 		// use literal strings here for `Type` instead of the defined constants in the volume package to keep this honest
1910 1915
 		// Validation of the actual `Mount` struct is done in another test is not needed here
1911
-		{mounttypes.Mount{Type: "volume", Target: destPath}, types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath}},
1912
-		{mounttypes.Mount{Type: "volume", Target: destPath + slash}, types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath}},
1913
-		{mounttypes.Mount{Type: "volume", Target: destPath, Source: "test1"}, types.MountPoint{Type: "volume", Name: "test1", RW: true, Destination: destPath}},
1914
-		{mounttypes.Mount{Type: "volume", Target: destPath, ReadOnly: true, Source: "test2"}, types.MountPoint{Type: "volume", Name: "test2", RW: false, Destination: destPath}},
1915 1916
 		{
1916
-			mounttypes.Mount{
1917
-				Type:   "volume",
1918
-				Target: destPath,
1919
-				Source: "test3",
1920
-				VolumeOptions: &mounttypes.VolumeOptions{
1921
-					DriverConfig: &mounttypes.Driver{Name: volume.DefaultDriverName},
1922
-				},
1923
-			},
1924
-			types.MountPoint{
1925
-				Driver:      volume.DefaultDriverName,
1926
-				Type:        "volume",
1927
-				Name:        "test3",
1928
-				RW:          true,
1929
-				Destination: destPath,
1930
-			},
1917
+			spec:     mounttypes.Mount{Type: "volume", Target: destPath},
1918
+			expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
1919
+		},
1920
+		{
1921
+			spec:     mounttypes.Mount{Type: "volume", Target: destPath + slash},
1922
+			expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
1923
+		},
1924
+		{
1925
+			spec:     mounttypes.Mount{Type: "volume", Target: destPath, Source: "test1"},
1926
+			expected: types.MountPoint{Type: "volume", Name: "test1", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
1927
+		},
1928
+		{
1929
+			spec:     mounttypes.Mount{Type: "volume", Target: destPath, ReadOnly: true, Source: "test2"},
1930
+			expected: types.MountPoint{Type: "volume", Name: "test2", RW: false, Destination: destPath, Mode: selinuxSharedLabel},
1931
+		},
1932
+		{
1933
+			spec:     mounttypes.Mount{Type: "volume", Target: destPath, Source: "test3", VolumeOptions: &mounttypes.VolumeOptions{DriverConfig: &mounttypes.Driver{Name: volume.DefaultDriverName}}},
1934
+			expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", Name: "test3", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
1931 1935
 		},
1932 1936
 	}
1933 1937
 
... ...
@@ -1938,19 +1943,22 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
1938 1938
 		defer os.RemoveAll(tmpDir1)
1939 1939
 		cases = append(cases, []testCase{
1940 1940
 			{
1941
-				mounttypes.Mount{
1941
+				spec: mounttypes.Mount{
1942 1942
 					Type:   "bind",
1943 1943
 					Source: tmpDir1,
1944 1944
 					Target: destPath,
1945 1945
 				},
1946
-				types.MountPoint{
1946
+				expected: types.MountPoint{
1947 1947
 					Type:        "bind",
1948 1948
 					RW:          true,
1949 1949
 					Destination: destPath,
1950 1950
 					Source:      tmpDir1,
1951 1951
 				},
1952 1952
 			},
1953
-			{mounttypes.Mount{Type: "bind", Source: tmpDir1, Target: destPath, ReadOnly: true}, types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir1}},
1953
+			{
1954
+				spec:     mounttypes.Mount{Type: "bind", Source: tmpDir1, Target: destPath, ReadOnly: true},
1955
+				expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir1},
1956
+			},
1954 1957
 		}...)
1955 1958
 
1956 1959
 		// for modes only supported on Linux
... ...
@@ -1963,19 +1971,40 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
1963 1963
 			c.Assert(mount.ForceMount("", tmpDir3, "none", "shared"), checker.IsNil)
1964 1964
 
1965 1965
 			cases = append(cases, []testCase{
1966
-				{mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath}, types.MountPoint{Type: "bind", RW: true, Destination: destPath, Source: tmpDir3}},
1967
-				{mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true}, types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3}},
1968
-				{mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true, BindOptions: &mounttypes.BindOptions{Propagation: "shared"}}, types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3, Propagation: "shared"}},
1966
+				{
1967
+					spec:     mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath},
1968
+					expected: types.MountPoint{Type: "bind", RW: true, Destination: destPath, Source: tmpDir3},
1969
+				},
1970
+				{
1971
+					spec:     mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true},
1972
+					expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3},
1973
+				},
1974
+				{
1975
+					spec:     mounttypes.Mount{Type: "bind", Source: tmpDir3, Target: destPath, ReadOnly: true, BindOptions: &mounttypes.BindOptions{Propagation: "shared"}},
1976
+					expected: types.MountPoint{Type: "bind", RW: false, Destination: destPath, Source: tmpDir3, Propagation: "shared"},
1977
+				},
1969 1978
 			}...)
1970 1979
 		}
1971 1980
 	}
1972 1981
 
1973 1982
 	if testEnv.DaemonPlatform() != "windows" { // Windows does not support volume populate
1974 1983
 		cases = append(cases, []testCase{
1975
-			{mounttypes.Mount{Type: "volume", Target: destPath, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}}, types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath}},
1976
-			{mounttypes.Mount{Type: "volume", Target: destPath + slash, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}}, types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath}},
1977
-			{mounttypes.Mount{Type: "volume", Target: destPath, Source: "test4", VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}}, types.MountPoint{Type: "volume", Name: "test4", RW: true, Destination: destPath}},
1978
-			{mounttypes.Mount{Type: "volume", Target: destPath, Source: "test5", ReadOnly: true, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}}, types.MountPoint{Type: "volume", Name: "test5", RW: false, Destination: destPath}},
1984
+			{
1985
+				spec:     mounttypes.Mount{Type: "volume", Target: destPath, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
1986
+				expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
1987
+			},
1988
+			{
1989
+				spec:     mounttypes.Mount{Type: "volume", Target: destPath + slash, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
1990
+				expected: types.MountPoint{Driver: volume.DefaultDriverName, Type: "volume", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
1991
+			},
1992
+			{
1993
+				spec:     mounttypes.Mount{Type: "volume", Target: destPath, Source: "test4", VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
1994
+				expected: types.MountPoint{Type: "volume", Name: "test4", RW: true, Destination: destPath, Mode: selinuxSharedLabel},
1995
+			},
1996
+			{
1997
+				spec:     mounttypes.Mount{Type: "volume", Target: destPath, Source: "test5", ReadOnly: true, VolumeOptions: &mounttypes.VolumeOptions{NoCopy: true}},
1998
+				expected: types.MountPoint{Type: "volume", Name: "test5", RW: false, Destination: destPath, Mode: selinuxSharedLabel},
1999
+			},
1979 2000
 		}...)
1980 2001
 	}
1981 2002
 
... ...
@@ -1990,11 +2019,11 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
1990 1990
 	ctx := context.Background()
1991 1991
 	apiclient := testEnv.APIClient()
1992 1992
 	for i, x := range cases {
1993
-		c.Logf("case %d - config: %v", i, x.cfg)
1993
+		c.Logf("case %d - config: %v", i, x.spec)
1994 1994
 		container, err := apiclient.ContainerCreate(
1995 1995
 			ctx,
1996 1996
 			&containertypes.Config{Image: testImg},
1997
-			&containertypes.HostConfig{Mounts: []mounttypes.Mount{x.cfg}},
1997
+			&containertypes.HostConfig{Mounts: []mounttypes.Mount{x.spec}},
1998 1998
 			&networktypes.NetworkingConfig{},
1999 1999
 			"")
2000 2000
 		require.NoError(c, err)
... ...
@@ -2035,12 +2064,12 @@ func (s *DockerSuite) TestContainersAPICreateMountsCreate(c *check.C) {
2035 2035
 		switch {
2036 2036
 
2037 2037
 		// Named volumes still exist after the container is removed
2038
-		case x.cfg.Type == "volume" && len(x.cfg.Source) > 0:
2038
+		case x.spec.Type == "volume" && len(x.spec.Source) > 0:
2039 2039
 			_, err := apiclient.VolumeInspect(ctx, mountPoint.Name)
2040 2040
 			require.NoError(c, err)
2041 2041
 
2042 2042
 		// Bind mounts are never removed with the container
2043
-		case x.cfg.Type == "bind":
2043
+		case x.spec.Type == "bind":
2044 2044
 
2045 2045
 		// anonymous volumes are removed
2046 2046
 		default:
... ...
@@ -334,6 +334,11 @@ func (v *localVolume) Path() string {
334 334
 	return v.path
335 335
 }
336 336
 
337
+// CachedPath returns the data location
338
+func (v *localVolume) CachedPath() string {
339
+	return v.path
340
+}
341
+
337 342
 // Mount implements the localVolume interface, returning the data location.
338 343
 // If there are any provided mount options, the resources will be mounted at this point
339 344
 func (v *localVolume) Mount(id string) (string, error) {