Add GetSELinuxSupport to mounter.

pull/8/head
Jan Safranek 2018-05-17 13:36:37 +02:00
parent c2b4fc99df
commit 598ca5accc
15 changed files with 159 additions and 21 deletions

View File

@ -116,6 +116,10 @@ func (mi *fakeMountInterface) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (mi *fakeMountInterface) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func fakeContainerMgrMountInt() mount.Interface {
return &fakeMountInterface{
[]mount.MountPoint{

View File

@ -159,3 +159,7 @@ func (m *execMounter) GetMountRefs(pathname string) ([]string, error) {
func (m *execMounter) GetFSGroup(pathname string) (int64, error) {
return m.wrappedMounter.GetFSGroup(pathname)
}
func (m *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
return m.wrappedMounter.GetSELinuxSupport(pathname)
}

View File

@ -172,3 +172,7 @@ func (fm *fakeMounter) GetMountRefs(pathname string) ([]string, error) {
func (fm *fakeMounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (fm *fakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}

View File

@ -106,3 +106,7 @@ func (mounter *execMounter) GetMountRefs(pathname string) ([]string, error) {
func (mounter *execMounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (mounter *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}

View File

@ -228,3 +228,7 @@ func (f *FakeMounter) GetMountRefs(pathname string) ([]string, error) {
func (f *FakeMounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("GetFSGroup not implemented")
}
func (f *FakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("GetSELinuxSupport not implemented")
}

View File

@ -114,6 +114,9 @@ type Interface interface {
GetMountRefs(pathname string) ([]string, error)
// GetFSGroup returns FSGroup of the path.
GetFSGroup(pathname string) (int64, error)
// GetSELinuxSupport returns true if given path is on a mount that supports
// SELinux.
GetSELinuxSupport(pathname string) (bool, error)
}
type Subpath struct {

View File

@ -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
// mount propagation.
func isShared(path string, filename string) (bool, error) {
infos, err := parseMountInfo(filename)
func isShared(mount string, mountInfoPath string) (bool, error) {
info, err := findMountInfo(mount, mountInfoPath)
if err != nil {
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
for _, opt := range info.optional {
if strings.HasPrefix(opt, "shared:") {
@ -624,6 +611,10 @@ type mountInfo struct {
mountPoint string
// list of "optional parameters", mount propagation is one of them
optional []string
// mount options
mountOptions []string
// super options: per-superblock options.
superOptions []string
}
// parseMountInfo parses /proc/xxx/mountinfo.
@ -642,22 +633,46 @@ func parseMountInfo(filename string) ([]mountInfo, error) {
}
// See `man proc` for authoritative description of format of the file.
fields := strings.Fields(line)
if len(fields) < 7 {
return nil, fmt.Errorf("wrong number of fields in (expected %d, got %d): %s", 8, len(fields), line)
if len(fields) < 10 {
return nil, fmt.Errorf("wrong number of fields in (expected %d, got %d): %s", 10, len(fields), line)
}
info := mountInfo{
mountPoint: fields[4],
optional: []string{},
mountPoint: fields[4],
mountOptions: strings.Split(fields[5], ","),
optional: []string{},
}
// All fields until "-" are "optional fields".
for i := 6; i < len(fields) && fields[i] != "-"; i++ {
info.optional = append(info.optional, fields[i])
}
superOpts := fields[len(fields)-1]
info.superOptions = strings.Split(superOpts, ",")
infos = append(infos, info)
}
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
// path is shared and bind-mounts it as rshared if needed. mountCmd and
// mountArgs are expected to contain mount-like command, doMakeRShared will add
@ -686,6 +701,27 @@ func doMakeRShared(path string, mountInfoFilename string) error {
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) {
newHostPath, err = doBindSubPath(mounter, subPath, os.Getpid())
// There is no action when the container starts. Bind-mount will be cleaned
@ -934,6 +970,10 @@ func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
return getMountRefsByDev(mounter, realpath)
}
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
return getSELinuxSupport(pathname, procMountInfoPath)
}
func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
realpath, err := filepath.EvalSymlinks(pathname)
if err != nil {

View File

@ -1399,8 +1399,10 @@ func TestParseMountInfo(t *testing.T) {
"simple bind mount",
"/var/lib/kubelet",
mountInfo{
mountPoint: "/var/lib/kubelet",
optional: []string{"shared:30"},
mountPoint: "/var/lib/kubelet",
optional: []string{"shared:30"},
mountOptions: []string{"rw", "relatime"},
superOptions: []string{"rw", "commit=30", "data=ordered"},
},
},
}
@ -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) {
defaultPerm := os.FileMode(0750)

View File

@ -134,3 +134,7 @@ func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (mounter *Mounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}

View File

@ -456,6 +456,11 @@ func (mounter *Mounter) GetFSGroup(pathname string) (int64, error) {
return 0, 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.
func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return doSafeMakeDir(pathname, base, perm)

View File

@ -343,3 +343,7 @@ func (mounter *NsenterMounter) GetFSGroup(pathname string) (int64, error) {
}
return getFSGroup(kubeletpath)
}
func (mounter *NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
return getSELinuxSupport(pathname, procMountInfoPath)
}

View File

@ -106,3 +106,7 @@ func (*NsenterMounter) GetMountRefs(pathname string) ([]string, error) {
func (*NsenterMounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (*NsenterMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}

View File

@ -99,6 +99,10 @@ func (mounter *fakeMounter) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (mounter *fakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func (mounter *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
name := path.Base(file)
if strings.HasPrefix(name, "mount") {

View File

@ -397,6 +397,10 @@ func (fftc *fakeFileTypeChecker) GetFSGroup(pathname string) (int64, error) {
return -1, errors.New("not implemented")
}
func (fftc *fakeFileTypeChecker) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func setUp() error {
err := os.MkdirAll("/tmp/ExistingFolder", os.FileMode(0755))
if err != nil {

View File

@ -131,6 +131,7 @@ type Mounter interface {
// idempotent.
SetUpAt(dir string, fsGroup *int64) error
// GetAttributes returns the attributes of the mounter.
// This function is called after SetUp()/SetUpAt().
GetAttributes() Attributes
}