diff --git a/go.mod b/go.mod index 20504293e..1cbd155e5 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/gopacket v1.1.19 github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 - github.com/mdlayher/vsock v1.1.1 + github.com/mdlayher/vsock v1.2.0 github.com/miekg/dns v1.1.50 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.24.1 @@ -22,7 +22,7 @@ require ( github.com/stretchr/testify v1.8.1 github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 + golang.org/x/sync v0.1.0 golang.org/x/sys v0.2.0 gvisor.dev/gvisor v0.0.0-20220908032458-edc830a43ba6 inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 @@ -33,7 +33,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/mdlayher/socket v0.2.0 // indirect + github.com/mdlayher/socket v0.4.0 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect diff --git a/go.sum b/go.sum index c63a22076..ee16676bc 100644 --- a/go.sum +++ b/go.sum @@ -56,10 +56,10 @@ github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/socket v0.2.0 h1:EY4YQd6hTAg2tcXF84p5DTHazShE50u5HeBzBaNgjkA= -github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= -github.com/mdlayher/vsock v1.1.1 h1:8lFuiXQnmICBrCIIA9PMgVSke6Fg6V4+r0v7r55k88I= -github.com/mdlayher/vsock v1.1.1/go.mod h1:Y43jzcy7KM3QB+/FK15pfqGxDMCMzUXWegEfIbSM18U= +github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= +github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= +github.com/mdlayher/vsock v1.2.0 h1:klRY9lndjmg6k/QWbX/ucQ3e2JFRm1M7vfG9hijbQ0A= +github.com/mdlayher/vsock v1.2.0/go.mod h1:w4kdSTQB9p1l/WwGmAs0V62qQ869qRYoongwgN+Y1HE= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -139,8 +139,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/vendor/github.com/mdlayher/socket/CHANGELOG.md b/vendor/github.com/mdlayher/socket/CHANGELOG.md index d16ae090b..0f24ed2c5 100644 --- a/vendor/github.com/mdlayher/socket/CHANGELOG.md +++ b/vendor/github.com/mdlayher/socket/CHANGELOG.md @@ -1,5 +1,43 @@ # CHANGELOG +## v0.4.0 + +**This is the first release of package socket that only supports Go 1.18+. +Users on older versions of Go must use v0.3.0.** + +- [Improvement]: drop support for older versions of Go so we can begin using + modern versions of `x/sys` and other dependencies. + +## v0.3.0 + +**This is the last release of package socket that supports Go 1.17 and below.** + +- [New API/API change] [PR](https://github.com/mdlayher/socket/pull/8): + numerous `socket.Conn` methods now support context cancelation. Future + releases will continue adding support as needed. + - New `ReadContext` and `WriteContext` methods. + - `Connect`, `Recvfrom`, `Recvmsg`, `Sendmsg`, and `Sendto` methods now accept + a context. + - `Sendto` parameter order was also fixed to match the underlying syscall. + +## v0.2.3 + +- [New API] [commit](https://github.com/mdlayher/socket/commit/a425d96e0f772c053164f8ce4c9c825380a98086): + `socket.Conn` has new `Pidfd*` methods for wrapping the `pidfd_*(2)` family of + system calls. + +## v0.2.2 + +- [New API] [commit](https://github.com/mdlayher/socket/commit/a2429f1dfe8ec2586df5a09f50ead865276cd027): + `socket.Conn` has new `IoctlKCM*` methods for wrapping `ioctl(2)` for `AF_KCM` + operations. + +## v0.2.1 + +- [New API] [commit](https://github.com/mdlayher/socket/commit/b18ddbe9caa0e34552b4409a3aa311cb460d2f99): + `socket.Conn` has a new `SetsockoptPacketMreq` method for wrapping + `setsockopt(2)` for `AF_PACKET` socket options. + ## v0.2.0 - [New API] [commit](https://github.com/mdlayher/socket/commit/6e912a68523c45e5fd899239f4b46c402dd856da): diff --git a/vendor/github.com/mdlayher/socket/README.md b/vendor/github.com/mdlayher/socket/README.md index 97ddcd617..2aa065cbb 100644 --- a/vendor/github.com/mdlayher/socket/README.md +++ b/vendor/github.com/mdlayher/socket/README.md @@ -12,3 +12,12 @@ used directly in end user applications. Any use of package socket should be guarded by build tags, as one would also use when importing the `syscall` or `golang.org/x/sys` packages. + +## Stability + +See the [CHANGELOG](./CHANGELOG.md) file for a description of changes between +releases. + +This package only supports the two most recent major versions of Go, mirroring +Go's own release policy. Older versions of Go may lack critical features and bug +fixes which are necessary for this package to function correctly. diff --git a/vendor/github.com/mdlayher/socket/conn.go b/vendor/github.com/mdlayher/socket/conn.go index d5ddcbf4a..ba1e5b41d 100644 --- a/vendor/github.com/mdlayher/socket/conn.go +++ b/vendor/github.com/mdlayher/socket/conn.go @@ -1,6 +1,8 @@ package socket import ( + "context" + "io" "os" "sync/atomic" "syscall" @@ -9,6 +11,15 @@ import ( "golang.org/x/sys/unix" ) +// Lock in an expected public interface for convenience. +var _ interface { + io.ReadWriteCloser + syscall.Conn + SetDeadline(t time.Time) error + SetReadDeadline(t time.Time) error + SetWriteDeadline(t time.Time) error +} = &Conn{} + // A Conn is a low-level network connection which integrates with Go's runtime // network poller to provide asynchronous I/O and deadline support. type Conn struct { @@ -20,6 +31,14 @@ type Conn struct { // descriptors such as those created by accept(2). name string + // Whether this is a streaming descriptor, as opposed to a + // packet-based descriptor like a UDP socket. + isStream bool + + // Whether a zero byte read indicates EOF. This is false for a + // message based socket connection. + zeroReadIsEOF bool + // Provides access to the underlying file registered with the runtime // network poller, and arbitrary raw I/O calls. fd *os.File @@ -77,14 +96,73 @@ func (c *Conn) CloseRead() error { return c.Shutdown(unix.SHUT_RD) } // use Close. func (c *Conn) CloseWrite() error { return c.Shutdown(unix.SHUT_WR) } -// Read implements io.Reader by reading directly from the underlying file -// descriptor. +// Read reads directly from the underlying file descriptor. func (c *Conn) Read(b []byte) (int, error) { return c.fd.Read(b) } -// Write implements io.Writer by writing directly to the underlying file -// descriptor. +// ReadContext reads from the underlying file descriptor with added support for +// context cancelation. +func (c *Conn) ReadContext(ctx context.Context, b []byte) (int, error) { + var ( + n int + err error + ) + + if c.isStream && len(b) > maxRW { + b = b[:maxRW] + } + doErr := c.read(ctx, "read", func(fd int) error { + n, err = unix.Read(fd, b) + return err + }) + + switch { + case doErr != nil: + return 0, doErr + case n == 0 && err == nil && c.zeroReadIsEOF: + return 0, io.EOF + } + + return n, os.NewSyscallError("read", err) +} + +// Write writes directly to the underlying file descriptor. func (c *Conn) Write(b []byte) (int, error) { return c.fd.Write(b) } +// WriteContext writes to the underlying file descriptor with added support for +// context cancelation. +func (c *Conn) WriteContext(ctx context.Context, b []byte) (int, error) { + var ( + n, nn int + err error + ) + + doErr := c.write(ctx, "write", func(fd int) error { + max := len(b) + if c.isStream && max-nn > maxRW { + max = nn + maxRW + } + + n, err = unix.Write(fd, b[nn:max]) + if n > 0 { + nn += n + } + if nn == len(b) { + return err + } + if n == 0 && err == nil { + err = io.ErrUnexpectedEOF + return nil + } + + return err + }) + if doErr != nil { + return 0, doErr + } + + return nn, os.NewSyscallError("write", err) +} + // SetDeadline sets both the read and write deadlines associated with the Conn. func (c *Conn) SetDeadline(t time.Time) error { return c.fd.SetDeadline(t) } @@ -184,7 +262,7 @@ func socket(domain, typ, proto int, name string) (*Conn, error) { } // No error, prepare the Conn. - return newConn(fd, name) + return New(fd, name) case !ready(err): // System call interrupted or not ready, try again. continue @@ -211,7 +289,7 @@ func socket(domain, typ, proto int, name string) (*Conn, error) { unix.CloseOnExec(fd) syscall.ForkLock.RUnlock() - return newConn(fd, name) + return New(fd, name) default: // Unhandled error. return nil, os.NewSyscallError("socket", err) @@ -230,7 +308,7 @@ func FileConn(f *os.File, name string) (*Conn, error) { switch err { case nil: // OK, ready to set up non-blocking I/O. - return newConn(fd, name) + return New(fd, name) case unix.EINVAL: // The kernel rejected our fcntl(2), fall back to separate dup(2) and // setting close on exec. @@ -248,18 +326,25 @@ func FileConn(f *os.File, name string) (*Conn, error) { unix.CloseOnExec(fd) syscall.ForkLock.RUnlock() - return newConn(fd, name) + return New(fd, name) default: // Any other errors. return nil, os.NewSyscallError("fcntl", err) } } -// TODO(mdlayher): consider exporting newConn as New? - -// newConn wraps an existing file descriptor to create a Conn. name should be a +// New wraps an existing file descriptor to create a Conn. name should be a // unique name for the socket type such as "netlink" or "vsock". -func newConn(fd int, name string) (*Conn, error) { +// +// Most callers should use Socket or FileConn to construct a Conn. New is +// intended for integrating with specific system calls which provide a file +// descriptor that supports asynchronous I/O. The file descriptor is immediately +// set to nonblocking mode and registered with Go's runtime network poller for +// future I/O operations. +// +// Unlike FileConn, New does not duplicate the existing file descriptor in any +// way. The returned Conn takes ownership of the underlying file descriptor. +func New(fd int, name string) (*Conn, error) { // All Conn I/O is nonblocking for integration with Go's runtime network // poller. Depending on the OS this might already be set but it can't hurt // to set it again. @@ -278,11 +363,20 @@ func newConn(fd int, name string) (*Conn, error) { return nil, err } - return &Conn{ + c := &Conn{ name: name, fd: f, rc: rc, - }, nil + } + + sotype, err := c.GetsockoptInt(unix.SOL_SOCKET, unix.SO_TYPE) + if err != nil { + return nil, err + } + + c.isStream = sotype == unix.SOCK_STREAM + c.zeroReadIsEOF = sotype != unix.SOCK_DGRAM && sotype != unix.SOCK_RAW + return c, nil } // Low-level methods which provide raw system call access. @@ -303,7 +397,7 @@ func (c *Conn) Accept(flags int) (*Conn, unix.Sockaddr, error) { err error ) - doErr := c.read(sysAccept, func(fd int) error { + doErr := c.read(context.Background(), sysAccept, func(fd int) error { // Either accept(2) or accept4(2) depending on the OS. nfd, sa, err = accept(fd, flags|socketFlags) return err @@ -318,7 +412,7 @@ func (c *Conn) Accept(flags int) (*Conn, unix.Sockaddr, error) { // Successfully accepted a connection, wrap it in a Conn for use by the // caller. - ac, err := newConn(nfd, c.name) + ac, err := New(nfd, c.name) if err != nil { return nil, nil, err } @@ -328,24 +422,15 @@ func (c *Conn) Accept(flags int) (*Conn, unix.Sockaddr, error) { // Bind wraps bind(2). func (c *Conn) Bind(sa unix.Sockaddr) error { - const op = "bind" - - var err error - doErr := c.control(op, func(fd int) error { - err = unix.Bind(fd, sa) - return err + return c.controlErr(context.Background(), "bind", func(fd int) error { + return unix.Bind(fd, sa) }) - if doErr != nil { - return doErr - } - - return os.NewSyscallError(op, err) } // Connect wraps connect(2). In order to verify that the underlying socket is // connected to a remote peer, Connect calls getpeername(2) and returns the // unix.Sockaddr from that call. -func (c *Conn) Connect(sa unix.Sockaddr) (unix.Sockaddr, error) { +func (c *Conn) Connect(ctx context.Context, sa unix.Sockaddr) (unix.Sockaddr, error) { const op = "connect" // TODO(mdlayher): it would seem that trying to connect to unbound vsock @@ -365,7 +450,7 @@ func (c *Conn) Connect(sa unix.Sockaddr) (unix.Sockaddr, error) { err error ) - doErr := c.write(op, func(fd int) error { + doErr := c.write(ctx, op, func(fd int) error { if atomic.AddUint32(&progress, 1) == 1 { // First call: initiate connect. return unix.Connect(fd, sa) @@ -374,6 +459,9 @@ func (c *Conn) Connect(sa unix.Sockaddr) (unix.Sockaddr, error) { // Subsequent calls: the runtime network poller indicates fd is // writable. Check for errno. errno, gerr := c.GetsockoptInt(unix.SOL_SOCKET, unix.SO_ERROR) + if err := ctx.Err(); err != nil { + return err + } if gerr != nil { return gerr } @@ -391,6 +479,9 @@ func (c *Conn) Connect(sa unix.Sockaddr) (unix.Sockaddr, error) { // poller to spuriously wake us and return errno 0 for SO_ERROR. // Make sure we are actually connected to a peer. peer, err := c.Getpeername() + if err := ctx.Err(); err != nil { + return err + } if err != nil { // internal/poll unconditionally goes back to WaitWrite. // Synthesize an error that will do the same for us. @@ -428,7 +519,7 @@ func (c *Conn) Getsockname() (unix.Sockaddr, error) { err error ) - doErr := c.control(op, func(fd int) error { + doErr := c.control(context.Background(), op, func(fd int) error { sa, err = unix.Getsockname(fd) return err }) @@ -448,7 +539,7 @@ func (c *Conn) Getpeername() (unix.Sockaddr, error) { err error ) - doErr := c.control(op, func(fd int) error { + doErr := c.control(context.Background(), op, func(fd int) error { sa, err = unix.Getpeername(fd) return err }) @@ -468,7 +559,7 @@ func (c *Conn) GetsockoptInt(level, opt int) (int, error) { err error ) - doErr := c.control(op, func(fd int) error { + doErr := c.control(context.Background(), op, func(fd int) error { value, err = unix.GetsockoptInt(fd, level, opt) return err }) @@ -481,22 +572,13 @@ func (c *Conn) GetsockoptInt(level, opt int) (int, error) { // Listen wraps listen(2). func (c *Conn) Listen(n int) error { - const op = "listen" - - var err error - doErr := c.control(op, func(fd int) error { - err = unix.Listen(fd, n) - return err + return c.controlErr(context.Background(), "listen", func(fd int) error { + return unix.Listen(fd, n) }) - if doErr != nil { - return doErr - } - - return os.NewSyscallError(op, err) } // Recvmsg wraps recvmsg(2). -func (c *Conn) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Sockaddr, error) { +func (c *Conn) Recvmsg(ctx context.Context, p, oob []byte, flags int) (int, int, int, unix.Sockaddr, error) { const op = "recvmsg" var ( @@ -505,19 +587,23 @@ func (c *Conn) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Sockaddr, err error ) - doErr := c.read(op, func(fd int) error { + doErr := c.read(ctx, op, func(fd int) error { n, oobn, recvflags, from, err = unix.Recvmsg(fd, p, oob, flags) return err }) - if doErr != nil { + + switch { + case doErr != nil: return 0, 0, 0, nil, doErr + case n == 0 && err == nil && c.zeroReadIsEOF: + return 0, 0, 0, nil, io.EOF } return n, oobn, recvflags, from, os.NewSyscallError(op, err) } -// Recvfrom wraps recvfrom(2) -func (c *Conn) Recvfrom(p []byte, flags int) (int, unix.Sockaddr, error) { +// Recvfrom wraps recvfrom(2). +func (c *Conn) Recvfrom(ctx context.Context, p []byte, flags int) (int, unix.Sockaddr, error) { const op = "recvfrom" var ( @@ -526,79 +612,58 @@ func (c *Conn) Recvfrom(p []byte, flags int) (int, unix.Sockaddr, error) { err error ) - doErr := c.read(op, func(fd int) error { + doErr := c.read(ctx, op, func(fd int) error { n, addr, err = unix.Recvfrom(fd, p, flags) return err }) - if doErr != nil { + + switch { + case doErr != nil: return 0, nil, doErr + case n == 0 && err == nil && c.zeroReadIsEOF: + return 0, nil, io.EOF } return n, addr, os.NewSyscallError(op, err) } // Sendmsg wraps sendmsg(2). -func (c *Conn) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error { - const op = "sendmsg" +func (c *Conn) Sendmsg(ctx context.Context, p, oob []byte, to unix.Sockaddr, flags int) (int, error) { + var ( + n int + err error + ) - var err error - doErr := c.write(op, func(fd int) error { - err = unix.Sendmsg(fd, p, oob, to, flags) + doErr := c.writeErr(ctx, "sendmsg", func(fd int) error { + n, err = unix.SendmsgN(fd, p, oob, to, flags) return err }) if doErr != nil { - return doErr + return 0, doErr } - return os.NewSyscallError(op, err) + return n, err } // Sendto wraps sendto(2). -func (c *Conn) Sendto(b []byte, to unix.Sockaddr, flags int) error { - const op = "sendto" - - var err error - doErr := c.write(op, func(fd int) error { - err = unix.Sendto(fd, b, flags, to) - return err +func (c *Conn) Sendto(ctx context.Context, p []byte, flags int, to unix.Sockaddr) error { + return c.writeErr(ctx, "sendto", func(fd int) error { + return unix.Sendto(fd, p, flags, to) }) - if doErr != nil { - return doErr - } - - return os.NewSyscallError(op, err) } // SetsockoptInt wraps setsockopt(2) for integer values. func (c *Conn) SetsockoptInt(level, opt, value int) error { - const op = "setsockopt" - - var err error - doErr := c.control(op, func(fd int) error { - err = unix.SetsockoptInt(fd, level, opt, value) - return err + return c.controlErr(context.Background(), "setsockopt", func(fd int) error { + return unix.SetsockoptInt(fd, level, opt, value) }) - if doErr != nil { - return doErr - } - - return os.NewSyscallError(op, err) } // Shutdown wraps shutdown(2). func (c *Conn) Shutdown(how int) error { - const op = "shutdown" - - var err error - doErr := c.control(op, func(fd int) error { - err = unix.Shutdown(fd, how) - return err + return c.controlErr(context.Background(), "shutdown", func(fd int) error { + return unix.Shutdown(fd, how) }) - if doErr != nil { - return doErr - } - - return os.NewSyscallError(op, err) } // Conn low-level read/write/control functions. These functions mirror the @@ -613,63 +678,158 @@ func (c *Conn) Shutdown(how int) error { // read executes f, a read function, against the associated file descriptor. // op is used to create an *os.SyscallError if the file descriptor is closed. -func (c *Conn) read(op string, f func(fd int) error) error { +// +// It obeys context cancelation and the context must not be nil. +func (c *Conn) read(ctx context.Context, op string, f func(fd int) error) error { if atomic.LoadUint32(&c.closed) != 0 { return os.NewSyscallError(op, unix.EBADF) } - return c.rc.Read(func(fd uintptr) bool { - return ready(f(int(fd))) + err := c.rc.Read(func(fd uintptr) bool { + select { + default: + return ready(f(int(fd))) + case <-ctx.Done(): + return ready(ctx.Err()) + } }) + if err := ctx.Err(); err != nil { + return err + } + return err +} + +// readErr wraps read to execute a function and capture its error result. +// This is a convenience wrapper for functions which don't return any extra +// values to capture in a closure. +// +// It obeys context cancelation and the context must not be nil. +func (c *Conn) readErr(ctx context.Context, op string, f func(fd int) error) error { + var err error + doErr := c.read(ctx, op, func(fd int) error { + return f(fd) + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) } // write executes f, a write function, against the associated file descriptor. // op is used to create an *os.SyscallError if the file descriptor is closed. -func (c *Conn) write(op string, f func(fd int) error) error { +// +// It obeys context cancelation and the context must not be nil. +func (c *Conn) write(ctx context.Context, op string, f func(fd int) error) error { if atomic.LoadUint32(&c.closed) != 0 { return os.NewSyscallError(op, unix.EBADF) } - return c.rc.Write(func(fd uintptr) bool { - return ready(f(int(fd))) + err := c.rc.Write(func(fd uintptr) (done bool) { + select { + default: + return ready(f(int(fd))) + case <-ctx.Done(): + return ready(ctx.Err()) + } + }) + if err := ctx.Err(); err != nil { + return err + } + return err +} + +// writeErr wraps write to execute a function and capture its error result. +// This is a convenience wrapper for functions which don't return any extra +// values to capture in a closure. +// +// It obeys context cancelation and the context must not be nil. +func (c *Conn) writeErr(ctx context.Context, op string, f func(fd int) error) error { + var err error + doErr := c.write(ctx, op, func(fd int) error { + return f(fd) }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) } // control executes f, a control function, against the associated file // descriptor. op is used to create an *os.SyscallError if the file descriptor // is closed. -func (c *Conn) control(op string, f func(fd int) error) error { +// +// It obeys context cancelation and the context must not be nil. +func (c *Conn) control(ctx context.Context, op string, f func(fd int) error) error { if atomic.LoadUint32(&c.closed) != 0 { return os.NewSyscallError(op, unix.EBADF) } - return c.rc.Control(func(fd uintptr) { + var cerr error + err := c.rc.Control(func(fd uintptr) { // Repeatedly attempt the syscall(s) invoked by f until completion is // indicated by the return value of ready. for { + if err := ctx.Err(); err != nil { + cerr = err + return + } if ready(f(int(fd))) { return } } }) + if cerr != nil { + err = cerr + } + + return err +} + +// controlErr wraps control to execute a function and capture its error result. +// This is a convenience wrapper for functions which don't return any extra +// values to capture in a closure. +// +// It obeys context cancelation and the context must not be nil. +func (c *Conn) controlErr(ctx context.Context, op string, f func(fd int) error) error { + var err error + doErr := c.control(ctx, op, func(fd int) error { + err = f(fd) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) } // ready indicates readiness based on the value of err. func ready(err error) bool { - // When a socket is in non-blocking mode, we might see a variety of errors: - // - EAGAIN: most common case for a socket read not being ready - // - EINPROGRESS: reported by some sockets when first calling connect - // - EINTR: system call interrupted, more frequently occurs in Go 1.14+ - // because goroutines can be asynchronously preempted - // - // Return false to let the poller wait for readiness. See the source code - // for internal/poll.FD.RawRead for more details. switch err { case unix.EAGAIN, unix.EINPROGRESS, unix.EINTR: - // Not ready. + // When a socket is in non-blocking mode, we might see a variety of errors: + // - EAGAIN: most common case for a socket read not being ready + // - EINPROGRESS: reported by some sockets when first calling connect + // - EINTR: system call interrupted, more frequently occurs in Go 1.14+ + // because goroutines can be asynchronously preempted + // + // Return false to let the poller wait for readiness. See the source code + // for internal/poll.FD.RawRead for more details. return false + case context.Canceled, context.DeadlineExceeded: + // The caller canceled the operation. + return true default: // Ready regardless of whether there was an error or no error. return true } } + +// Darwin and FreeBSD can't read or write 2GB+ files at a time, +// even on 64-bit systems. +// The same is true of socket implementations on many systems. +// See golang.org/issue/7812 and golang.org/issue/16266. +// Use 1GB instead of, say, 2GB-1, to keep subsequent reads aligned. +const maxRW = 1 << 30 diff --git a/vendor/github.com/mdlayher/socket/conn_linux.go b/vendor/github.com/mdlayher/socket/conn_linux.go index 275f641c1..d0d9ee529 100644 --- a/vendor/github.com/mdlayher/socket/conn_linux.go +++ b/vendor/github.com/mdlayher/socket/conn_linux.go @@ -4,6 +4,7 @@ package socket import ( + "context" "os" "unsafe" @@ -11,6 +12,78 @@ import ( "golang.org/x/sys/unix" ) +// IoctlKCMClone wraps ioctl(2) for unix.KCMClone values, but returns a Conn +// rather than a raw file descriptor. +func (c *Conn) IoctlKCMClone() (*Conn, error) { + const op = "ioctl" + + var ( + info *unix.KCMClone + err error + ) + + doErr := c.control(context.Background(), op, func(fd int) error { + info, err = unix.IoctlKCMClone(fd) + return err + }) + if doErr != nil { + return nil, doErr + } + if err != nil { + return nil, os.NewSyscallError(op, err) + } + + // Successful clone, wrap in a Conn for use by the caller. + return New(int(info.Fd), c.name) +} + +// IoctlKCMAttach wraps ioctl(2) for unix.KCMAttach values. +func (c *Conn) IoctlKCMAttach(info unix.KCMAttach) error { + return c.controlErr(context.Background(), "ioctl", func(fd int) error { + return unix.IoctlKCMAttach(fd, info) + }) +} + +// IoctlKCMUnattach wraps ioctl(2) for unix.KCMUnattach values. +func (c *Conn) IoctlKCMUnattach(info unix.KCMUnattach) error { + return c.controlErr(context.Background(), "ioctl", func(fd int) error { + return unix.IoctlKCMUnattach(fd, info) + }) +} + +// PidfdGetfd wraps pidfd_getfd(2) for a Conn which wraps a pidfd, but returns a +// Conn rather than a raw file descriptor. +func (c *Conn) PidfdGetfd(targetFD, flags int) (*Conn, error) { + const op = "pidfd_getfd" + + var ( + outFD int + err error + ) + + doErr := c.control(context.Background(), op, func(fd int) error { + outFD, err = unix.PidfdGetfd(fd, targetFD, flags) + return err + }) + if doErr != nil { + return nil, doErr + } + if err != nil { + return nil, os.NewSyscallError(op, err) + } + + // Successful getfd, wrap in a Conn for use by the caller. + return New(outFD, c.name) +} + +// PidfdSendSignal wraps pidfd_send_signal(2) for a Conn which wraps a Linux +// pidfd. +func (c *Conn) PidfdSendSignal(sig unix.Signal, info *unix.Siginfo, flags int) error { + return c.controlErr(context.Background(), "pidfd_send_signal", func(fd int) error { + return unix.PidfdSendSignal(fd, sig, info, flags) + }) +} + // SetBPF attaches an assembled BPF program to a Conn. func (c *Conn) SetBPF(filter []bpf.RawInstruction) error { // We can't point to the first instruction in the array if no instructions @@ -33,23 +106,24 @@ func (c *Conn) RemoveBPF() error { return c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_DETACH_FILTER, 0) } +// SetsockoptPacketMreq wraps setsockopt(2) for unix.PacketMreq values. +func (c *Conn) SetsockoptPacketMreq(level, opt int, mreq *unix.PacketMreq) error { + return c.controlErr(context.Background(), "setsockopt", func(fd int) error { + return unix.SetsockoptPacketMreq(fd, level, opt, mreq) + }) +} + // SetsockoptSockFprog wraps setsockopt(2) for unix.SockFprog values. func (c *Conn) SetsockoptSockFprog(level, opt int, fprog *unix.SockFprog) error { - const op = "setsockopt" - - var err error - doErr := c.control(op, func(fd int) error { - err = unix.SetsockoptSockFprog(fd, level, opt, fprog) - return err + return c.controlErr(context.Background(), "setsockopt", func(fd int) error { + return unix.SetsockoptSockFprog(fd, level, opt, fprog) }) - if doErr != nil { - return doErr - } - - return os.NewSyscallError(op, err) } -// GetSockoptTpacketStats wraps getsockopt(2) for getting TpacketStats +// TODO(mdlayher): we accidentally called these GetSockopt rather than +// Getsockopt by package unix convention. Consider fixing. + +// GetSockoptTpacketStats wraps getsockopt(2) for unix.TpacketStats values. func (c *Conn) GetSockoptTpacketStats(level, name int) (*unix.TpacketStats, error) { const op = "getsockopt" @@ -58,17 +132,18 @@ func (c *Conn) GetSockoptTpacketStats(level, name int) (*unix.TpacketStats, erro err error ) - doErr := c.control(op, func(fd int) error { + doErr := c.control(context.Background(), op, func(fd int) error { stats, err = unix.GetsockoptTpacketStats(fd, level, name) return err }) if doErr != nil { - return stats, doErr + return nil, doErr } + return stats, os.NewSyscallError(op, err) } -// GetSockoptTpacketStatsV3 wraps getsockopt(2) for getting TpacketStatsV3 +// GetSockoptTpacketStatsV3 wraps getsockopt(2) for unix.TpacketStatsV3 values. func (c *Conn) GetSockoptTpacketStatsV3(level, name int) (*unix.TpacketStatsV3, error) { const op = "getsockopt" @@ -77,12 +152,20 @@ func (c *Conn) GetSockoptTpacketStatsV3(level, name int) (*unix.TpacketStatsV3, err error ) - doErr := c.control(op, func(fd int) error { + doErr := c.control(context.Background(), op, func(fd int) error { stats, err = unix.GetsockoptTpacketStatsV3(fd, level, name) return err }) if doErr != nil { - return stats, doErr + return nil, doErr } + return stats, os.NewSyscallError(op, err) } + +// Waitid wraps waitid(2). +func (c *Conn) Waitid(idType int, info *unix.Siginfo, options int, rusage *unix.Rusage) error { + return c.readErr(context.Background(), "waitid", func(fd int) error { + return unix.Waitid(idType, fd, info, options, rusage) + }) +} diff --git a/vendor/github.com/mdlayher/vsock/CHANGELOG.md b/vendor/github.com/mdlayher/vsock/CHANGELOG.md index f0916c51d..55f058cd1 100644 --- a/vendor/github.com/mdlayher/vsock/CHANGELOG.md +++ b/vendor/github.com/mdlayher/vsock/CHANGELOG.md @@ -1,9 +1,17 @@ # CHANGELOG -## Unreleased +# v1.2.0 + +**This is the first release of package vsock that only supports Go 1.18+. Users +on older versions of Go must use v1.1.1.** + +- [Improvement]: drop support for older versions of Go so we can begin using + modern versions of `x/sys` and other dependencies. ## v1.1.1 +**This is the last release of package vsock that supports Go 1.17 and below.** + - [Bug Fix] [commit](https://github.com/mdlayher/vsock/commit/ead86435c244d5d6baad549a6df0557ada3f4401): fix build on non-UNIX platforms such as Windows. This is a no-op change on Linux but provides a friendlier experience for non-Linux users. diff --git a/vendor/github.com/mdlayher/vsock/README.md b/vendor/github.com/mdlayher/vsock/README.md index 6395502bf..b1ec4cfbe 100644 --- a/vendor/github.com/mdlayher/vsock/README.md +++ b/vendor/github.com/mdlayher/vsock/README.md @@ -3,8 +3,9 @@ Package `vsock` provides access to Linux VM sockets (`AF_VSOCK`) for communication between a hypervisor and its virtual machines. MIT Licensed. -For more information about VM sockets, check out my blog about -[Linux VM sockets in Go](https://mdlayher.com/blog/linux-vm-sockets-in-go/). +For more information about VM sockets, see my blog about +[Linux VM sockets in Go](https://mdlayher.com/blog/linux-vm-sockets-in-go/) or +the [QEMU wiki page on virtio-vsock](http://wiki.qemu-project.org/Features/VirtioVsock). ## Stability @@ -15,39 +16,6 @@ This package has a stable v1 API and any future breaking changes will prompt the release of a new major version. Features and bug fixes will continue to occur in the v1.x.x series. -In order to reduce the maintenance burden, this package is only supported on -Go 1.12+. Older versions of Go lack critical features and APIs which are -necessary for this package to function correctly. - -**If you depend on this package in your applications, please use Go modules.** - -## Requirements - -**It's possible these requirements are out of date. PRs are welcome.** - -To make use of VM sockets with QEMU and virtio-vsock, you must have: - -- a Linux hypervisor with kernel 4.8+ -- a Linux virtual machine on that hypervisor with kernel 4.8+ -- QEMU 2.8+ on the hypervisor, running the virtual machine - -Before using VM sockets, following modules must be removed on hypervisor: - -- `modprobe -r vmw_vsock_vmci_transport` -- `modprobe -r vmw_vsock_virtio_transport_common` -- `modprobe -r vsock` - -Once removed, `vhost_vsock` module needs to be enabled on hypervisor: - -- `modprobe vhost_vsock` - -On VM, you have to enable `vmw_vsock_virtio_transport` module. This module should automatically load during boot when the vsock device is detected. - -To utilize VM sockets, VM needs to be powered on with following `-device` flag: - -- `-device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=3` - -Check out the -[QEMU wiki page on virtio-vsock](http://wiki.qemu-project.org/Features/VirtioVsock) -for more details. More detail on setting up this environment will be provided -in the future. +This package only supports the two most recent major versions of Go, mirroring +Go's own release policy. Older versions of Go may lack critical features and bug +fixes which are necessary for this package to function correctly. diff --git a/vendor/github.com/mdlayher/vsock/conn_linux.go b/vendor/github.com/mdlayher/vsock/conn_linux.go index 4e6dd6a0b..6029d547e 100644 --- a/vendor/github.com/mdlayher/vsock/conn_linux.go +++ b/vendor/github.com/mdlayher/vsock/conn_linux.go @@ -4,6 +4,8 @@ package vsock import ( + "context" + "github.com/mdlayher/socket" "golang.org/x/sys/unix" ) @@ -24,7 +26,7 @@ func dial(cid, port uint32, _ *Config) (*Conn, error) { } sa := &unix.SockaddrVM{CID: cid, Port: port} - rsa, err := c.Connect(sa) + rsa, err := c.Connect(context.Background(), sa) if err != nil { _ = c.Close() return nil, err diff --git a/vendor/golang.org/x/sync/errgroup/errgroup.go b/vendor/golang.org/x/sync/errgroup/errgroup.go index 4c0850a45..cbee7a4e2 100644 --- a/vendor/golang.org/x/sync/errgroup/errgroup.go +++ b/vendor/golang.org/x/sync/errgroup/errgroup.go @@ -61,8 +61,8 @@ func (g *Group) Wait() error { // It blocks until the new goroutine can be added without the number of // active goroutines in the group exceeding the configured limit. // -// The first call to return a non-nil error cancels the group; its error will be -// returned by Wait. +// The first call to return a non-nil error cancels the group's context, if the +// group was created by calling WithContext. The error will be returned by Wait. func (g *Group) Go(f func() error) { if g.sem != nil { g.sem <- token{} diff --git a/vendor/modules.txt b/vendor/modules.txt index 65a973453..3be90cb03 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -45,11 +45,11 @@ github.com/insomniacslk/dhcp/rfc1035label # github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 ## explicit; go 1.17 github.com/linuxkit/virtsock/pkg/hvsock -# github.com/mdlayher/socket v0.2.0 -## explicit; go 1.17 +# github.com/mdlayher/socket v0.4.0 +## explicit; go 1.18 github.com/mdlayher/socket -# github.com/mdlayher/vsock v1.1.1 -## explicit; go 1.17 +# github.com/mdlayher/vsock v1.2.0 +## explicit; go 1.18 github.com/mdlayher/vsock # github.com/miekg/dns v1.1.50 ## explicit; go 1.14 @@ -153,7 +153,7 @@ golang.org/x/net/internal/iana golang.org/x/net/internal/socket golang.org/x/net/ipv4 golang.org/x/net/ipv6 -# golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 +# golang.org/x/sync v0.1.0 ## explicit golang.org/x/sync/errgroup # golang.org/x/sys v0.2.0