Merge pull request #61480 from gnufied/fix-unix-socket-subpath-mount

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Fix unix socket subpath mount

Fixes https://github.com/kubernetes/kubernetes/issues/61377

```release-note
Fix mounting of UNIX sockets(and other special files) in subpaths
```
pull/8/head
Kubernetes Submit Queue 2018-03-25 20:40:28 -07:00 committed by GitHub
commit 0aa9a69bf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 3 deletions

View File

@ -54,7 +54,9 @@ const (
// place for subpath mounts
containerSubPathDirectoryName = "volume-subpaths"
// syscall.Openat flags used to traverse directories not following symlinks
nofollowFlags = syscall.O_RDONLY | syscall.O_NOFOLLOW
nofollowFlags = unix.O_RDONLY | unix.O_NOFOLLOW
// flags for getting file descriptor without following the symlink
openFDFlags = unix.O_NOFOLLOW | unix.O_PATH
)
// Mounter provides the default implementation of mount.Interface
@ -1074,7 +1076,9 @@ func findExistingPrefix(base, pathname string) (string, []string, error) {
}
}()
for i, dir := range dirs {
childFD, err := syscall.Openat(fd, dir, syscall.O_RDONLY, 0)
// Using O_PATH here will prevent hangs in case user replaces directory with
// fifo
childFD, err := syscall.Openat(fd, dir, unix.O_PATH, 0)
if err != nil {
if os.IsNotExist(err) {
return currentPath, dirs[i:], nil
@ -1136,11 +1140,21 @@ func doSafeOpen(pathname string, base string) (int, error) {
}
glog.V(5).Infof("Opening path %s", currentPath)
childFD, err = syscall.Openat(parentFD, seg, nofollowFlags, 0)
childFD, err = syscall.Openat(parentFD, seg, openFDFlags, 0)
if err != nil {
return -1, fmt.Errorf("cannot open %s: %s", currentPath, err)
}
var deviceStat unix.Stat_t
err := unix.Fstat(childFD, &deviceStat)
if err != nil {
return -1, fmt.Errorf("Error running fstat on %s with %v", currentPath, err)
}
fileFmt := deviceStat.Mode & syscall.S_IFMT
if fileFmt == syscall.S_IFLNK {
return -1, fmt.Errorf("Unexpected symlink found %s", currentPath)
}
// Close parentFD
if err = syscall.Close(parentFD); err != nil {
return -1, fmt.Errorf("closing fd for %q failed: %v", filepath.Dir(currentPath), err)

View File

@ -21,6 +21,7 @@ package mount
import (
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
"reflect"
@ -1179,6 +1180,44 @@ func TestBindSubPath(t *testing.T) {
},
expectError: false,
},
{
name: "subpath-mounting-unix-socket",
prepare: func(base string) ([]string, string, string, error) {
volpath, subpathMount := getTestPaths(base)
mounts := []string{subpathMount}
if err := os.MkdirAll(volpath, defaultPerm); err != nil {
return nil, "", "", err
}
if err := os.MkdirAll(subpathMount, defaultPerm); err != nil {
return nil, "", "", err
}
testSocketFile := filepath.Join(volpath, "mount_test.sock")
_, err := net.Listen("unix", testSocketFile)
return mounts, volpath, testSocketFile, err
},
expectError: false,
},
{
name: "subpath-mounting-fifo",
prepare: func(base string) ([]string, string, string, error) {
volpath, subpathMount := getTestPaths(base)
mounts := []string{subpathMount}
if err := os.MkdirAll(volpath, defaultPerm); err != nil {
return nil, "", "", err
}
if err := os.MkdirAll(subpathMount, defaultPerm); err != nil {
return nil, "", "", err
}
testFifo := filepath.Join(volpath, "mount_test.fifo")
err := syscall.Mkfifo(testFifo, 0)
return mounts, volpath, testFifo, err
},
expectError: false,
},
}
for _, test := range tests {
@ -1308,6 +1347,7 @@ func TestParseMountInfo(t *testing.T) {
func TestSafeOpen(t *testing.T) {
defaultPerm := os.FileMode(0750)
tests := []struct {
name string
// Function that prepares directory structure for the test under given
@ -1435,6 +1475,32 @@ func TestSafeOpen(t *testing.T) {
"test",
true,
},
{
"mounting-unix-socket",
func(base string) error {
testSocketFile := filepath.Join(base, "mount_test.sock")
_, err := net.Listen("unix", testSocketFile)
if err != nil {
return fmt.Errorf("Error preparing socket file %s with %v", testSocketFile, err)
}
return nil
},
"mount_test.sock",
false,
},
{
"mounting-unix-socket-in-middle",
func(base string) error {
testSocketFile := filepath.Join(base, "mount_test.sock")
_, err := net.Listen("unix", testSocketFile)
if err != nil {
return fmt.Errorf("Error preparing socket file %s with %v", testSocketFile, err)
}
return nil
},
"mount_test.sock/bar",
true,
},
}
for _, test := range tests {
@ -1551,6 +1617,17 @@ func TestFindExistingPrefix(t *testing.T) {
[]string{"test", "directory"},
false,
},
{
"with-fifo-in-middle",
func(base string) error {
testFifo := filepath.Join(base, "mount_test.fifo")
return syscall.Mkfifo(testFifo, 0)
},
"mount_test.fifo/directory",
"",
nil,
true,
},
}
for _, test := range tests {