Unverified Commit d8f9e51c authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #64432 from jsafrane/automated-cherry-pick-of-#64026-upstream-release-1.10

Automatic merge from submit-queue. Automated cherry pick of #64026: Add SELinux support to CSI Cherry pick of #64026 on release-1.10. #64026: Add GetSELinuxSupport to mounter. ```release-note Fixed SELinux relabeling of CSI volumes. ```
parents 74697e1d 9f2b3c56
......@@ -19,6 +19,7 @@ limitations under the License.
package cm
import (
"errors"
"fmt"
"io/ioutil"
"os"
......@@ -107,6 +108,10 @@ func (mi *fakeMountInterface) SafeMakeDir(_, _ string, _ os.FileMode) error {
return nil
}
func (mi *fakeMountInterface) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
func fakeContainerMgrMountInt() mount.Interface {
return &fakeMountInterface{
[]mount.MountPoint{
......
......@@ -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 {
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.
package mount
import (
"errors"
"fmt"
"os"
"reflect"
......@@ -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 {
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
func (mounter *execMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return nil
}
func (mounter *execMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("not implemented")
}
......@@ -17,6 +17,7 @@ limitations under the License.
package mount
import (
"errors"
"os"
"path/filepath"
"sync"
......@@ -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 {
return nil
}
func (f *FakeMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, errors.New("GetSELinuxSupport not implemented")
}
......@@ -109,6 +109,9 @@ type Interface interface {
// subpath starts. On the other hand, Interface.CleanSubPaths must be called
// when the pod finishes.
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 {
......
......@@ -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
......@@ -926,6 +962,10 @@ func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMo
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
func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
glog.V(4).Infof("Creating directory %q within base %q", pathname, base)
......
......@@ -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)
......
......@@ -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 {
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) {
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.
func (mounter *Mounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
return doSafeMakeDir(pathname, base, perm)
......
......@@ -323,3 +323,7 @@ func (mounter *NsenterMounter) PrepareSafeSubpath(subPath Subpath) (newHostPath
func (mounter *NsenterMounter) SafeMakeDir(pathname string, base string, perm os.FileMode) error {
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,
func (*NsenterMounter) CleanSubPaths(podDir string, volumeName string) error {
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 {
return nil
}
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") {
......
......@@ -252,10 +252,18 @@ func (c *csiMountMgr) SetUpAt(dir string, fsGroup *int64) error {
}
func (c *csiMountMgr) GetAttributes() volume.Attributes {
mounter := c.plugin.host.GetMounter(c.plugin.GetPluginName())
path := c.GetPath()
supportSelinux, err := mounter.GetSELinuxSupport(path)
if err != nil {
glog.V(2).Info(log("error checking for SELinux support: %s", err))
// Best guess
supportSelinux = false
}
return volume.Attributes{
ReadOnly: c.readOnly,
Managed: !c.readOnly,
SupportsSELinux: false,
SupportsSELinux: supportSelinux,
}
}
......
......@@ -17,6 +17,7 @@ limitations under the License.
package host_path
import (
"errors"
"fmt"
"os"
"testing"
......@@ -388,6 +389,10 @@ func (fftc *fakeFileTypeChecker) SafeMakeDir(_, _ string, _ os.FileMode) error {
return nil
}
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 {
......
......@@ -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
}
......
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