diff --git a/runsc/fsgofer/fsgofer.go b/runsc/fsgofer/fsgofer.go index 80c1e2a45..b974b486e 100644 --- a/runsc/fsgofer/fsgofer.go +++ b/runsc/fsgofer/fsgofer.go @@ -48,6 +48,9 @@ const ( openFlags = unix.O_NOFOLLOW | unix.O_CLOEXEC allowedOpenFlags = unix.O_TRUNC + + // UNIX_PATH_MAX as defined in include/uapi/linux/un.h. + unixPathMax = 108 ) // join is equivalent to path.Join() but skips path.Clean() which is expensive. @@ -1148,6 +1151,14 @@ func (l *localFile) Connect(socketType p9.SocketType) (*fd.FD, error) { return nil, unix.ECONNREFUSED } + // TODO(gvisor.dev/issue/1003): Due to different app vs replacement + // mappings, the app path may have fit in the sockaddr, but we can't + // fit f.path in our sockaddr. We'd need to redirect through a shorter + // path in order to actually connect to this socket. + if len(l.hostPath) >= unixPathMax { + return nil, unix.ECONNREFUSED + } + stype, ok := socketType.ToLinux() if !ok { return nil, unix.ENXIO @@ -1163,10 +1174,7 @@ func (l *localFile) Connect(socketType p9.SocketType) (*fd.FD, error) { return nil, err } - // Use /proc/self/fd to refer to the socket file. This is faster and more - // secure because it avoids the host path walk. It also helps avoid the - // UNIX_PATH_MAX bytes limit on the path, in case path is too long. - sa := unix.SockaddrUnix{Name: filepath.Join("/proc/self/fd", strconv.Itoa(l.file.FD()))} + sa := unix.SockaddrUnix{Name: l.hostPath} if err := unix.Connect(f, &sa); err != nil { _ = unix.Close(f) return nil, err diff --git a/runsc/fsgofer/lisafs.go b/runsc/fsgofer/lisafs.go index 31802bd6a..56d64798d 100644 --- a/runsc/fsgofer/lisafs.go +++ b/runsc/fsgofer/lisafs.go @@ -684,6 +684,15 @@ func (fd *controlFDLisa) Connect(sockType uint32) (int, error) { return -1, unix.EPERM } + // TODO(gvisor.dev/issue/1003): Due to different app vs replacement + // mappings, the app path may have fit in the sockaddr, but we can't fit + // hostPath in our sockaddr. We'd need to redirect through a shorter path + // in order to actually connect to this socket. + hostPath := fd.Node().FilePath() + if len(hostPath) >= unixPathMax { + return -1, unix.EINVAL + } + if !isSockTypeSupported(sockType) { return -1, unix.ENXIO } @@ -693,10 +702,7 @@ func (fd *controlFDLisa) Connect(sockType uint32) (int, error) { return -1, err } - // Use /proc/self/fd to refer to the socket file. This is faster and more - // secure because it avoids the host path walk. It also helps avoid the - // UNIX_PATH_MAX bytes limit on the path, in case path is too long. - sa := unix.SockaddrUnix{Name: filepath.Join("/proc/self/fd", strconv.Itoa(fd.hostFD))} + sa := unix.SockaddrUnix{Name: hostPath} if err := unix.Connect(sock, &sa); err != nil { unix.Close(sock) return -1, err @@ -710,6 +716,19 @@ func (fd *controlFDLisa) BindAt(name string, sockType uint32, mode linux.FileMod return nil, linux.Statx{}, nil, -1, unix.EPERM } + // Because there is no "bindat" syscall in Linux, we must create an + // absolute path to the socket we are creating, + socketPath := filepath.Join(fd.Node().FilePath(), name) + + // TODO(gvisor.dev/issue/1003): Due to different app vs replacement + // mappings, the app path may have fit in the sockaddr, but we can't fit + // hostPath in our sockaddr. We'd need to redirect through a shorter path + // in order to actually connect to this socket. + if len(socketPath) >= unixPathMax { + log.Warningf("BindAt called with name too long: %q (len=%d)", socketPath, len(socketPath)) + return nil, linux.Statx{}, nil, -1, unix.EINVAL + } + // Only the following types are supported. if !isSockTypeSupported(sockType) { return nil, linux.Statx{}, nil, -1, unix.ENXIO @@ -732,11 +751,6 @@ func (fd *controlFDLisa) BindAt(name string, sockType uint32, mode linux.FileMod return nil, linux.Statx{}, nil, -1, err } - // Because there is no "bindat" syscall in Linux, we must create an - // absolute path to the socket we are creating. But go through /proc/self/fd - // to avoid host path walk of the entire host path. It also helps avoid the - // UNIX_PATH_MAX bytes limit on the path, in case path is too long. - socketPath := filepath.Join("/proc/self/fd", strconv.Itoa(fd.hostFD), name) if err := unix.Bind(sockFD, &unix.SockaddrUnix{Name: socketPath}); err != nil { return nil, linux.Statx{}, nil, -1, err }