mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
@@ -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",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -18,6 +18,7 @@ go_library(
|
||||
"//test:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/atomicbitops",
|
||||
"//pkg/cleanup",
|
||||
"//pkg/control/client",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user