From c319b360d134cff66000fd036fce8b3816c296ea Mon Sep 17 00:00:00 2001 From: Robert Tonic Date: Mon, 29 Jul 2019 14:57:14 -0700 Subject: First pass at implementing Unix Domain Socket support. No tests. This commit adds support for detecting the socket file type, connecting to a Unix Domain Socket, and providing bidirectional communication (without file descriptor transfer support). --- runsc/fsgofer/filter/config.go | 28 ++++++++++++++++ runsc/fsgofer/fsgofer.go | 73 ++++++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 21 deletions(-) (limited to 'runsc/fsgofer') 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. -- cgit v1.2.3