Commit 3e4c7d40 authored by Jan Safranek's avatar Jan Safranek

Add GetSELinuxSupport to mounter.

parent c5f46f9e
...@@ -19,6 +19,7 @@ limitations under the License. ...@@ -19,6 +19,7 @@ limitations under the License.
package cm package cm
import ( import (
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
...@@ -107,6 +108,10 @@ func (mi *fakeMountInterface) SafeMakeDir(_, _ string, _ os.FileMode) error { ...@@ -107,6 +108,10 @@ func (mi *fakeMountInterface) SafeMakeDir(_, _ string, _ os.FileMode) error {
return nil return nil
} }
func (mi *fakeMountInterface) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func fakeContainerMgrMountInt() mount.Interface { func fakeContainerMgrMountInt() mount.Interface {
return &fakeMountInterface{ return &fakeMountInterface{
[]mount.MountPoint{ []mount.MountPoint{
......
...@@ -151,3 +151,7 @@ func (m *execMounter) CleanSubPaths(podDir string, volumeName string) error { ...@@ -151,3 +151,7 @@ func (m *execMounter) CleanSubPaths(podDir string, volumeName string) error {
func (m *execMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error { func (m *execMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return m.wrappedMounter.SafeMakeDir(pathname, base, perm) return m.wrappedMounter.SafeMakeDir(pathname, base, perm)
} }
func (m *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
return m.wrappedMounter.GetSELinuxSupport(pathname)
}
...@@ -19,6 +19,7 @@ limitations under the License. ...@@ -19,6 +19,7 @@ limitations under the License.
package mount package mount
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"reflect" "reflect"
...@@ -163,3 +164,7 @@ func (fm *fakeMounter) CleanSubPaths(podDir string, volumeName string) error { ...@@ -163,3 +164,7 @@ func (fm *fakeMounter) CleanSubPaths(podDir string, volumeName string) error {
func (fm *fakeMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error { func (fm *fakeMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil return nil
} }
func (fm *fakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
...@@ -98,3 +98,7 @@ func (mounter *execMounter) CleanSubPaths(podDir string, volumeName string) erro ...@@ -98,3 +98,7 @@ func (mounter *execMounter) CleanSubPaths(podDir string, volumeName string) erro
func (mounter *execMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error { func (mounter *execMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil return nil
} }
func (mounter *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package mount package mount
import ( import (
"errors"
"os" "os"
"path/filepath" "path/filepath"
"sync" "sync"
...@@ -214,3 +215,7 @@ func (f *FakeMounter) CleanSubPaths(podDir string, volumeName string) error { ...@@ -214,3 +215,7 @@ func (f *FakeMounter) CleanSubPaths(podDir string, volumeName string) error {
func (mounter *FakeMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error { func (mounter *FakeMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil return nil
} }
func (f *FakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("GetSELinuxSupport not implemented")
}
...@@ -109,6 +109,9 @@ type Interface interface { ...@@ -109,6 +109,9 @@ type Interface interface {
// subpath starts. On the other hand, Interface.CleanSubPaths must be called // subpath starts. On the other hand, Interface.CleanSubPaths must be called
// when the pod finishes. // when the pod finishes.
PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error)
// GetSELinuxSupport returns true if given path is on a mount that supports
// SELinux.
GetSELinuxSupport(pathname string) (bool, error)
} }
type Subpath struct { type Subpath struct {
......
...@@ -591,25 +591,12 @@ func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) { ...@@ -591,25 +591,12 @@ func (mounter *SafeFormatAndMount) GetDiskFormat(disk string) (string, error) {
// isShared returns true, if given path is on a mount point that has shared // isShared returns true, if given path is on a mount point that has shared
// mount propagation. // mount propagation.
func isShared(path string, filename string) (bool, error) { func isShared(mount string, mountInfoPath string) (bool, error) {
infos, err := parseMountInfo(filename) info, err := findMountInfo(mount, mountInfoPath)
if err != nil { if err != nil {
return false, err return false, err
} }
// process /proc/xxx/mountinfo in backward order and find the first mount
// point that is prefix of 'path' - that's the mount where path resides
var info *mountInfo
for i := len(infos) - 1; i >= 0; i-- {
if strings.HasPrefix(path, infos[i].mountPoint) {
info = &infos[i]
break
}
}
if info == nil {
return false, fmt.Errorf("cannot find mount point for %q", path)
}
// parse optional parameters // parse optional parameters
for _, opt := range info.optional { for _, opt := range info.optional {
if strings.HasPrefix(opt, "shared:") { if strings.HasPrefix(opt, "shared:") {
...@@ -624,6 +611,10 @@ type mountInfo struct { ...@@ -624,6 +611,10 @@ type mountInfo struct {
mountPoint string mountPoint string
// list of "optional parameters", mount propagation is one of them // list of "optional parameters", mount propagation is one of them
optional []string optional []string
// mount options
mountOptions []string
// super options: per-superblock options.
superOptions []string
} }
// parseMountInfo parses /proc/xxx/mountinfo. // parseMountInfo parses /proc/xxx/mountinfo.
...@@ -642,22 +633,46 @@ func parseMountInfo(filename string) ([]mountInfo, error) { ...@@ -642,22 +633,46 @@ func parseMountInfo(filename string) ([]mountInfo, error) {
} }
// See `man proc` for authoritative description of format of the file. // See `man proc` for authoritative description of format of the file.
fields := strings.Fields(line) fields := strings.Fields(line)
if len(fields) < 7 { if len(fields) < 10 {
return nil, fmt.Errorf("wrong number of fields in (expected %d, got %d): %s", 8, len(fields), line) return nil, fmt.Errorf("wrong number of fields in (expected %d, got %d): %s", 10, len(fields), line)
} }
info := mountInfo{ info := mountInfo{
mountPoint: fields[4], mountPoint: fields[4],
optional: []string{}, mountOptions: strings.Split(fields[5], ","),
optional: []string{},
} }
// All fields until "-" are "optional fields". // All fields until "-" are "optional fields".
for i := 6; i < len(fields) && fields[i] != "-"; i++ { for i := 6; i < len(fields) && fields[i] != "-"; i++ {
info.optional = append(info.optional, fields[i]) info.optional = append(info.optional, fields[i])
} }
superOpts := fields[len(fields)-1]
info.superOptions = strings.Split(superOpts, ",")
infos = append(infos, info) infos = append(infos, info)
} }
return infos, nil return infos, nil
} }
func findMountInfo(path, mountInfoPath string) (mountInfo, error) {
infos, err := parseMountInfo(mountInfoPath)
if err != nil {
return mountInfo{}, err
}
// process /proc/xxx/mountinfo in backward order and find the first mount
// point that is prefix of 'path' - that's the mount where path resides
var info *mountInfo
for i := len(infos) - 1; i >= 0; i-- {
if pathWithinBase(path, infos[i].mountPoint) {
info = &infos[i]
break
}
}
if info == nil {
return mountInfo{}, fmt.Errorf("cannot find mount point for %q", path)
}
return *info, nil
}
// doMakeRShared is common implementation of MakeRShared on Linux. It checks if // doMakeRShared is common implementation of MakeRShared on Linux. It checks if
// path is shared and bind-mounts it as rshared if needed. mountCmd and // path is shared and bind-mounts it as rshared if needed. mountCmd and
// mountArgs are expected to contain mount-like command, doMakeRShared will add // mountArgs are expected to contain mount-like command, doMakeRShared will add
...@@ -686,6 +701,27 @@ func doMakeRShared(path string, mountInfoFilename string) error { ...@@ -686,6 +701,27 @@ func doMakeRShared(path string, mountInfoFilename string) error {
return nil return nil
} }
// getSELinuxSupport is common implementation of GetSELinuxSupport on Linux.
func getSELinuxSupport(path string, mountInfoFilename string) (bool, error) {
info, err := findMountInfo(path, mountInfoFilename)
if err != nil {
return false, err
}
// "seclabel" can be both in mount options and super options.
for _, opt := range info.superOptions {
if opt == "seclabel" {
return true, nil
}
}
for _, opt := range info.mountOptions {
if opt == "seclabel" {
return true, nil
}
}
return false, nil
}
func (mounter *Mounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) { func (mounter *Mounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, cleanupAction func(), err error) {
newHostPath, err = doBindSubPath(mounter, subPath, os.Getpid()) newHostPath, err = doBindSubPath(mounter, subPath, os.Getpid())
// There is no action when the container starts. Bind-mount will be cleaned // There is no action when the container starts. Bind-mount will be cleaned
...@@ -926,6 +962,10 @@ func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMo ...@@ -926,6 +962,10 @@ func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMo
return doSafeMakeDir(pathname, base, perm) return doSafeMakeDir(pathname, base, perm)
} }
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
return getSELinuxSupport(pathname, procMountInfoPath)
}
// This implementation is shared between Linux and NsEnterMounter // This implementation is shared between Linux and NsEnterMounter
func doSafeMakeDir(pathname string, base string, perm os.FileMode) error { func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
glog.V(4).Infof("Creating directory %q within base %q", pathname, base) glog.V(4).Infof("Creating directory %q within base %q", pathname, base)
......
...@@ -1399,8 +1399,10 @@ func TestParseMountInfo(t *testing.T) { ...@@ -1399,8 +1399,10 @@ func TestParseMountInfo(t *testing.T) {
"simple bind mount", "simple bind mount",
"/var/lib/kubelet", "/var/lib/kubelet",
mountInfo{ mountInfo{
mountPoint: "/var/lib/kubelet", mountPoint: "/var/lib/kubelet",
optional: []string{"shared:30"}, optional: []string{"shared:30"},
mountOptions: []string{"rw", "relatime"},
superOptions: []string{"rw", "commit=30", "data=ordered"},
}, },
}, },
} }
...@@ -1427,6 +1429,53 @@ func TestParseMountInfo(t *testing.T) { ...@@ -1427,6 +1429,53 @@ func TestParseMountInfo(t *testing.T) {
} }
} }
func TestGetSELinuxSupport(t *testing.T) {
info :=
`62 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
78 62 0:41 / /tmp rw,nosuid,nodev shared:30 - tmpfs tmpfs rw,seclabel
83 63 0:44 / /var/lib/bar rw,relatime - tmpfs tmpfs rw
227 62 253:0 /var/lib/docker/devicemapper /var/lib/docker/devicemapper rw,relatime - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
150 23 1:58 / /media/nfs_vol rw,relatime shared:89 - nfs4 172.18.4.223:/srv/nfs rw,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=172.18.4.223,local_lock=none,addr=172.18.4.223
`
tempDir, filename, err := writeFile(info)
if err != nil {
t.Fatalf("cannot create temporary file: %v", err)
}
defer os.RemoveAll(tempDir)
tests := []struct {
name string
mountPoint string
expectedResult bool
}{
{
"ext4 on /",
"/",
true,
},
{
"tmpfs on /var/lib/bar",
"/var/lib/bar",
false,
},
{
"nfsv4",
"/media/nfs_vol",
false,
},
}
for _, test := range tests {
out, err := getSELinuxSupport(test.mountPoint, filename)
if err != nil {
t.Errorf("Test %s failed with error: %s", test.name, err)
}
if test.expectedResult != out {
t.Errorf("Test %s failed: expected %v, got %v", test.name, test.expectedResult, out)
}
}
}
func TestSafeOpen(t *testing.T) { func TestSafeOpen(t *testing.T) {
defaultPerm := os.FileMode(0750) defaultPerm := os.FileMode(0750)
......
...@@ -121,3 +121,7 @@ func (mounter *Mounter) CleanSubPaths(podDir string, volumeName string) error { ...@@ -121,3 +121,7 @@ func (mounter *Mounter) CleanSubPaths(podDir string, volumeName string) error {
func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error { func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil return nil
} }
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
...@@ -438,6 +438,11 @@ func getAllParentLinks(path string) ([]string, error) { ...@@ -438,6 +438,11 @@ func getAllParentLinks(path string) ([]string, error) {
return links, nil return links, nil
} }
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
// Windows does not support SELinux.
return false, nil
}
// SafeMakeDir makes sure that the created directory does not escape given base directory mis-using symlinks. // SafeMakeDir makes sure that the created directory does not escape given base directory mis-using symlinks.
func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error { func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return doSafeMakeDir(pathname, base, perm) return doSafeMakeDir(pathname, base, perm)
......
...@@ -323,3 +323,7 @@ func (mounter *NsenterMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath ...@@ -323,3 +323,7 @@ func (mounter *NsenterMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath
func (mounter *NsenterMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error { func (mounter *NsenterMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return doSafeMakeDir(pathname, base, perm) return doSafeMakeDir(pathname, base, perm)
} }
func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
return getSELinuxSupport(pathname, procMountInfoPath)
}
...@@ -98,3 +98,7 @@ func (*NsenterMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string, ...@@ -98,3 +98,7 @@ func (*NsenterMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath string,
func (*NsenterMounter) CleanSubPaths(podDir string, volumeName string) error { func (*NsenterMounter) CleanSubPaths(podDir string, volumeName string) error {
return nil return nil
} }
func (*NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
...@@ -91,6 +91,10 @@ func (mounter *fakeMounter) SafeMakeDir(_, _ string, _ os.FileMode) error { ...@@ -91,6 +91,10 @@ func (mounter *fakeMounter) SafeMakeDir(_, _ string, _ os.FileMode) error {
return nil return nil
} }
func (mounter *fakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func (mounter *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) { func (mounter *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
name := path.Base(file) name := path.Base(file)
if strings.HasPrefix(name, "mount") { if strings.HasPrefix(name, "mount") {
......
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package host_path package host_path
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"testing" "testing"
...@@ -388,6 +389,10 @@ func (fftc *fakeFileTypeChecker) SafeMakeDir(_, _ string, _ os.FileMode) error { ...@@ -388,6 +389,10 @@ func (fftc *fakeFileTypeChecker) SafeMakeDir(_, _ string, _ os.FileMode) error {
return nil return nil
} }
func (fftc *fakeFileTypeChecker) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func setUp() error { func setUp() error {
err := os.MkdirAll("/tmp/ExistingFolder", os.FileMode(0755)) err := os.MkdirAll("/tmp/ExistingFolder", os.FileMode(0755))
if err != nil { if err != nil {
......
...@@ -131,6 +131,7 @@ type Mounter interface { ...@@ -131,6 +131,7 @@ type Mounter interface {
// idempotent. // idempotent.
SetUpAt(dir string, fsGroup *int64) error SetUpAt(dir string, fsGroup *int64) error
// GetAttributes returns the attributes of the mounter. // GetAttributes returns the attributes of the mounter.
// This function is called after SetUp()/SetUpAt().
GetAttributes() Attributes GetAttributes() Attributes
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment