diff options
-rw-r--r-- | pkg/fd/fd.go | 16 | ||||
-rw-r--r-- | runsc/fsgofer/filter/config.go | 28 | ||||
-rw-r--r-- | runsc/fsgofer/fsgofer.go | 73 |
3 files changed, 96 insertions, 21 deletions
diff --git a/pkg/fd/fd.go b/pkg/fd/fd.go index 83bcfe220..c3acd0fe2 100644 --- a/pkg/fd/fd.go +++ b/pkg/fd/fd.go @@ -22,6 +22,7 @@ import ( "runtime" "sync/atomic" "syscall" + "net" ) // ReadWriter implements io.ReadWriter, io.ReaderAt, and io.WriterAt for fd. It @@ -185,6 +186,21 @@ func OpenAt(dir *FD, path string, flags int, mode uint32) (*FD, error) { return New(f), nil } +// OpenUnix TODO: DOC +func OpenUnix(path string) (*FD, error) { + addr, _ := net.ResolveUnixAddr("unix", path) + f, err := net.DialUnix("unix", nil, addr); if err != nil { + return nil, fmt.Errorf("unable to open socket: %q, err: %v", path, err) + } + fConnd, err := f.File(); if err != nil { + return nil, fmt.Errorf("unable to convert to os.File: %q, err: %v", path, err) + } + fdConnd, err := NewFromFile(fConnd); if err != nil { + return nil, fmt.Errorf("unable to convert os.File to fd.FD: %q, err: %v", path, err) + } + return fdConnd, nil +} + // Close closes the file descriptor contained in the FD. // // Close is safe to call multiple times, but will return an error after the diff --git a/runsc/fsgofer/filter/config.go b/runsc/fsgofer/filter/config.go index 8ddfa77d6..71f387bd0 100644 --- a/runsc/fsgofer/filter/config.go +++ b/runsc/fsgofer/filter/config.go @@ -26,6 +26,31 @@ import ( // allowedSyscalls is the set of syscalls executed by the gofer. var allowedSyscalls = seccomp.SyscallRules{ syscall.SYS_ACCEPT: {}, + syscall.SYS_SOCKET: []seccomp.Rule{ + { + seccomp.AllowValue(syscall.AF_UNIX), + }, + }, + syscall.SYS_CONNECT: []seccomp.Rule{ + { + seccomp.AllowAny{}, + }, + }, + syscall.SYS_SETSOCKOPT: []seccomp.Rule{ + { + seccomp.AllowAny{}, + }, + }, + syscall.SYS_GETSOCKNAME: []seccomp.Rule{ + { + seccomp.AllowAny{}, + }, + }, + syscall.SYS_GETPEERNAME: []seccomp.Rule{ + { + seccomp.AllowAny{}, + }, + }, syscall.SYS_ARCH_PRCTL: []seccomp.Rule{ {seccomp.AllowValue(linux.ARCH_GET_FS)}, {seccomp.AllowValue(linux.ARCH_SET_FS)}, @@ -83,6 +108,9 @@ var allowedSyscalls = seccomp.SyscallRules{ seccomp.AllowAny{}, seccomp.AllowValue(syscall.F_GETFD), }, + { + seccomp.AllowAny{}, + }, }, syscall.SYS_FSTAT: {}, syscall.SYS_FSTATFS: {}, diff --git a/runsc/fsgofer/fsgofer.go b/runsc/fsgofer/fsgofer.go index 7c4d2b94e..3a78d20a3 100644 --- a/runsc/fsgofer/fsgofer.go +++ b/runsc/fsgofer/fsgofer.go @@ -54,6 +54,7 @@ const ( regular fileType = iota directory symlink + socket unknown ) @@ -66,6 +67,8 @@ func (f fileType) String() string { return "directory" case symlink: return "symlink" + case socket: + return "socket" } return "unknown" } @@ -124,30 +127,56 @@ func (a *attachPoint) Attach() (p9.File, error) { if err != nil { return nil, fmt.Errorf("stat file %q, err: %v", a.prefix, err) } - mode := syscall.O_RDWR - if a.conf.ROMount || (stat.Mode&syscall.S_IFMT) == syscall.S_IFDIR { - mode = syscall.O_RDONLY - } - // Open the root directory. - f, err := fd.Open(a.prefix, openFlags|mode, 0) - if err != nil { - return nil, fmt.Errorf("unable to open file %q, err: %v", a.prefix, err) - } + // Apply the S_IFMT bitmask so we can detect file type appropriately + fmtStat := stat.Mode & syscall.S_IFMT - a.attachedMu.Lock() - defer a.attachedMu.Unlock() - if a.attached { - f.Close() - return nil, fmt.Errorf("attach point already attached, prefix: %s", a.prefix) - } + switch fmtStat{ + case syscall.S_IFSOCK: + // Attempt to open a connection. Bubble up the failures. + f, err := fd.OpenUnix(a.prefix); if err != nil { + return nil, err + } - rv, err := newLocalFile(a, f, a.prefix, stat) - if err != nil { - return nil, err + // Close the connection if the UDS is already attached. + a.attachedMu.Lock() + defer a.attachedMu.Unlock() + if a.attached { + f.Close() + return nil, fmt.Errorf("attach point already attached, prefix: %s", a.prefix) + } + a.attached = true + + // Return a localFile object to the caller with the UDS FD included. + return newLocalFile(a, f, a.prefix, stat) + + default: + // Default to Read/Write permissions. + mode := syscall.O_RDWR + // If the configuration is Read Only & the mount point is a directory, + // set the mode to Read Only. + if a.conf.ROMount || fmtStat == syscall.S_IFDIR { + mode = syscall.O_RDONLY + } + + // Open the mount point & capture the FD. + f, err := fd.Open(a.prefix, openFlags|mode, 0) + if err != nil { + return nil, fmt.Errorf("unable to open file %q, err: %v", a.prefix, err) + } + + // If the mount point has already been attached, close the FD. + a.attachedMu.Lock() + defer a.attachedMu.Unlock() + if a.attached { + f.Close() + return nil, fmt.Errorf("attach point already attached, prefix: %s", a.prefix) + } + a.attached = true + + // Return a localFile object to the caller with the mount point FD + return newLocalFile(a, f, a.prefix, stat) } - a.attached = true - return rv, nil } // makeQID returns a unique QID for the given stat buffer. @@ -304,6 +333,8 @@ func getSupportedFileType(stat syscall.Stat_t) (fileType, error) { ft = directory case syscall.S_IFLNK: ft = symlink + case syscall.S_IFSOCK: + ft = socket default: return unknown, syscall.EPERM } @@ -1026,7 +1057,7 @@ func (l *localFile) Flush() error { // Connect implements p9.File. func (l *localFile) Connect(p9.ConnectFlags) (*fd.FD, error) { - return nil, syscall.ECONNREFUSED + return fd.OpenUnix(l.hostPath) } // Close implements p9.File. |