Handle large control socket paths.

UDS connect and bind fail when the socket path being used is more than 107 in
length. Shorten the path using procfs: "/proc/self/fd/{parentFD}/{sockName)"

This avoids falling back to using abstract sockets in some instances.

Suggested-by: Andrei Vagin <avagin@google.com>
PiperOrigin-RevId: 565557006
This commit is contained in:
Ayush Ranjan
2023-09-14 20:56:26 -07:00
committed by gVisor bot
parent e01d4387d2
commit b192bf3736
4 changed files with 40 additions and 3 deletions
+2
View File
@@ -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",
],
)
+22 -2
View File
@@ -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
+1
View File
@@ -18,6 +18,7 @@ go_library(
"//test:__subpackages__",
],
deps = [
"//pkg/abi/linux",
"//pkg/atomicbitops",
"//pkg/cleanup",
"//pkg/control/client",
+15 -1
View File
@@ -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)
}