Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automated cherry pick of #61480: Use O_PATH to avoid errors on Openat #61723

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 17 additions & 3 deletions pkg/util/mount/mount_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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
Expand Down Expand Up @@ -977,7 +979,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
Expand Down Expand Up @@ -1039,11 +1043,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)
Expand Down
77 changes: 77 additions & 0 deletions pkg/util/mount/mount_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package mount
import (
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -1131,6 +1132,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 {
Expand Down Expand Up @@ -1260,6 +1299,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
Expand Down Expand Up @@ -1387,6 +1427,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 {
Expand Down Expand Up @@ -1503,6 +1569,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 {
Expand Down