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>
| ... | ... |
@@ -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) {
|