diff --git a/pkg/control/server/BUILD b/pkg/control/server/BUILD index 9dacc65b3..9f4592f73 100644 --- a/pkg/control/server/BUILD +++ b/pkg/control/server/BUILD @@ -10,9 +10,11 @@ go_library( srcs = ["server.go"], visibility = ["//:sandbox"], deps = [ + "//pkg/abi/linux", "//pkg/log", "//pkg/sync", "//pkg/unet", "//pkg/urpc", + "@org_golang_x_sys//unix:go_default_library", ], ) diff --git a/pkg/control/server/server.go b/pkg/control/server/server.go index ec6bb618f..906725a09 100644 --- a/pkg/control/server/server.go +++ b/pkg/control/server/server.go @@ -21,9 +21,13 @@ implementations of the control interface. package server import ( + "fmt" "os" + "path/filepath" "time" + "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/unet" @@ -143,17 +147,33 @@ func CreateFromFD(fd int) (*Server, error) { // with the given address, which must must be unique and a valid // abstract socket name. func Create(addr string) (*Server, error) { - socket, err := unet.Bind(addr, false) + socket, err := CreateSocket(addr) if err != nil { return nil, err } - return New(socket), nil + return CreateFromFD(socket) } // CreateSocket creates a socket that can be used with control server, // but doesn't start control server. 'addr' must be a valid and unique // abstract socket name. Returns socket's FD, -1 in case of error. func CreateSocket(addr string) (int, error) { + if addr[0] != 0 && len(addr) >= linux.UnixPathMax { + // This is not an abstract socket path. It is a filesystem path. + // UDS bind fails when the len(socket path) >= UNIX_PATH_MAX. Instead + // try opening the parent and attempt to shorten the path via procfs. + dirFD, err := unix.Open(filepath.Dir(addr), unix.O_RDONLY|unix.O_DIRECTORY, 0) + if err != nil { + return -1, fmt.Errorf("failed to open parent directory of %q", addr) + } + defer unix.Close(dirFD) + name := filepath.Base(addr) + addr = fmt.Sprintf("/proc/self/fd/%d/%s", dirFD, name) + if len(addr) >= linux.UnixPathMax { + // Urgh... This is just doomed to fail. Ask caller to use a shorter name. + return -1, fmt.Errorf("socket name %q is too long, use a shorter name", name) + } + } socket, err := unet.Bind(addr, false) if err != nil { return -1, err diff --git a/runsc/sandbox/BUILD b/runsc/sandbox/BUILD index 23c2aee66..c1989d913 100644 --- a/runsc/sandbox/BUILD +++ b/runsc/sandbox/BUILD @@ -18,6 +18,7 @@ go_library( "//test:__subpackages__", ], deps = [ + "//pkg/abi/linux", "//pkg/atomicbitops", "//pkg/cleanup", "//pkg/control/client", diff --git a/runsc/sandbox/sandbox.go b/runsc/sandbox/sandbox.go index 5d57d48bc..9e6f96358 100644 --- a/runsc/sandbox/sandbox.go +++ b/runsc/sandbox/sandbox.go @@ -34,6 +34,7 @@ import ( specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/syndtr/gocapability/capability" "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/atomicbitops" "gvisor.dev/gvisor/pkg/cleanup" "gvisor.dev/gvisor/pkg/control/client" @@ -87,6 +88,7 @@ func createControlSocket(rootDir, id string) (string, int, error) { log.Debugf("Using socket file %q", path) return path, fd, nil } + log.Debugf("Failed to create socket file %q: %v", path, err) } return "", -1, fmt.Errorf("unable to find location to write socket file") } @@ -602,7 +604,19 @@ func (s *Sandbox) PortForward(opts *boot.PortForwardOpts) error { func (s *Sandbox) sandboxConnect() (*urpc.Client, error) { log.Debugf("Connecting to sandbox %q", s.ID) - conn, err := client.ConnectTo(s.ControlAddress) + addr := s.ControlAddress + if addr[0] != 0 && len(addr) >= linux.UnixPathMax { + // This is not an abstract socket path. It is a filesystem path. + // UDS connect fails when the len(socket path) >= UNIX_PATH_MAX. Instead + // open the socket using open(2) and use /proc to refer to the open FD. + sockFD, err := unix.Open(addr, unix.O_PATH, 0) + if err != nil { + return nil, fmt.Errorf("failed to open socket at %q", addr) + } + defer unix.Close(sockFD) + addr = filepath.Join("/proc/self/fd", fmt.Sprintf("%d", sockFD)) + } + conn, err := client.ConnectTo(addr) if err != nil { return nil, s.connError(err) }